iOS приложение с фреймворком падает на устройстве: dyld: Library not loaded, Xcode 6 Beta
Причина проблемы
Ошибка dyld: Library not loaded на реальном устройстве при работающем симуляторе — классическая проблема с динамическими фреймворками в iOS. Дело в том, что симулятор и устройство имеют разную архитектуру (x86_64 vs arm64/armv7), и Xcode собирает фреймворк только для архитектуры симулятора, если не настроить правильно сборку. Кроме того, динамические фреймворки требуют корректной встраивания (embedding) в приложение, чтобы система могла их найти во время запуска.
Решение шаг за шагом
Вот проверенный алгоритм, который решит вашу проблему. Выполните все шаги последовательно.
Шаг 1. Проверьте архитектуры фреймворка
Убедитесь, что ваш фреймворк собирается для всех необходимых архитектур. В Xcode выберите проект фреймворка, перейдите в Build Settings и найдите параметр Architectures. Установите значение Standard architectures (arm64, armv7, armv7s) — $(ARCHS_STANDARD). Также проверьте Build Active Architecture Only — для Debug можно оставить Yes (чтобы быстрее собирать), но для Release обязательно No.
Шаг 2. Правильно встройте фреймворк в приложение
В основном таргете вашего приложения:
- Перейдите в General → Frameworks, Libraries, and Embedded Content.
- Нажмите
+и добавьтеMyFramework.framework. - В выпадающем списке справа выберите Embed & Sign (или Embed Without Signing, если у вас нет подписи).
Это гарантирует, что фреймворк будет скопирован в папку Frameworks внутри вашего .app-пакета.
Шаг 3. Настройте Runpath Search Paths
В Build Settings основного таргета найдите Runpath Search Paths и добавьте:
@executable_path/Frameworks
Это путь, по которому dyld будет искать динамические библиотеки во время выполнения.
Шаг 4. Проверьте фазу сборки (Build Phases)
Перейдите в Build Phases основного таргета. Убедитесь, что в секции Embed Frameworks (или Copy Files) присутствует ваш фреймворк. Если нет — добавьте вручную через + → New Copy Files Phase → Destination: Frameworks → добавьте MyFramework.framework.
Шаг 5. Чистая сборка и запуск на устройстве
Перед запуском на устройстве обязательно сделайте:
Product → Clean Build Folder (Option+Shift+Cmd+K)
Product → Build (Cmd+B)
Product → Run (Cmd+R)
Дополнительная проверка
Если проблема осталась, выполните в терминале для проверки, какие архитектуры содержит собранный фреймворк:
lipo -info /путь/к/MyFramework.framework/MyFramework
Вы должны увидеть arm64 armv7 armv7s. Если там только x86_64 — фреймворк собран только для симулятора. В таком случае добавьте в скрипт сборки (Build Phases → Run Script) следующий код для объединения архитектур:
#!/bin/sh
FRAMEWORK_NAME="MyFramework"
FRAMEWORK_PATH="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/${FRAMEWORK_NAME}.framework"
lipo -create "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}" -output "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}"
После всех этих шагов приложение должно успешно запускаться на устройстве. Если всё ещё падает — проверьте, что вы используете последнюю версию Xcode (на момент написания ответа Xcode 6 Beta имела много багов, и обновление могло исправить проблему).
<<Альтернативный подход: использование статической библиотеки
Если динамический фреймворк продолжает вызывать проблемы (особенно в ранних бета-версиях Xcode), вы можете временно переключиться на статическую библиотеку. Это полностью устранит ошибку dyld, так как код библиотеки будет включён непосредственно в исполняемый файл приложения.
Как перейти на статическую библиотеку:
- Создайте новый таргет: File → New → Target → Cocoa Touch Static Library.
- Перенесите весь код из динамического фреймворка в статическую библиотеку.
- В настройках статической библиотеки установите Mach-O Type =
Static Library. - В основном приложении добавьте статическую библиотеку в General → Frameworks, Libraries, and Embedded Content — выберите Do Not Embed.
- В Build Settings основного таргета добавьте путь к заголовкам библиотеки в User Header Search Paths и установите флаг
-ObjCв Other Linker Flags (для корректной загрузки Objective-C и Swift кода).
Почему это сработает?
Статические библиотеки не требуют динамической загрузки во время выполнения — они встраиваются в бинарник на этапе компиляции. Это обходит ошибку dyld, но имеет недостаток: размер приложения увеличивается, и вы не сможете использовать один и тот же фреймворк для расширений (Today Extension, Watch App) без дублирования кода.
Это временное решение для Xcode 6 Beta. В более поздних версиях Xcode и iOS динамические фреймворки работают стабильно, и лучше вернуться к ним для модульности и переиспользования кода.