Проблемы с привязкой iOS-приложения к пользовательской платформе

Я разбиваю большое приложение iOS на несколько фреймворков и столкнулся со следующей проблемой:

Как правильно включить пользовательский проект инфраструктуры Cocoa Touch в проект приложения iOS, чтобы все правильно связывалось?

  1. Я создал структуру проекта со всем необходимым кодом внутри.
  2. Для проверки я создал образец рабочего пространства и добавил в него проект фреймворка.
  3. Затем я создал образец проекта приложения для iOS с несколькими строками кода, используя фреймворк, а также добавил проект в рабочую область.

Теперь я перехожу к связующей части.

Первая попытка:

  1. Откройте настройки цели приложения в Xcode, выберите панель Info и добавьте платформу в раздел Linked Frameworks and Libraries.

  2. Чтобы все было хорошо, я также выбираю только что добавленный фреймворк в проекте приложения и меняю его Location с Relative to Group на Relative to Build Products. Под местоположением отображается как ../Debug-iphonesimulator/MyFramework.framework

  3. Текущая схема <Simulator, Debug>, я нажимаю Run, и все работает как надо — приложение регистрирует, что использует фреймворк в порядке.

  4. Теперь я очищаю папку сборки и меняю схему на <Simulator, Release>.

  5. Затем я нажимаю Run, проекты начинают создаваться, а затем привязка приложения завершается ошибкой:

Undefined symbols for architecture x86_64: <a function from the framework> referenced from: <a file in the app>.

Изучив папку сборки, я вижу, что фреймворк был собран правильно, находится в .../Build/Products/Release-iphonesimulator/... и представляет собой толстый двоичный файл с i386 и x86_64 внутри.

Как правильно связать фреймворк, чтобы он работал в любой конфигурации (отладка, выпуск) и на симуляторе, и, конечно же, на устройствах?

Чтобы уточнить, я намерен разрабатывать как фреймворки, так и приложение одновременно, поэтому такое решение, как, например. CocoaPods делает это путем предварительной сборки толстых фреймворков, что кажется не очень практичным (если только я что-то не упустил из-за отсутствия достаточного опыта работы с CocoaPods).


Ниже приведен вывод ошибочной фазы Link:

Ld /Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Intermediates/MyApp.build/Release-iphonesimulator/MyApp.build/Objects-normal/x86_64/MyApp normal x86_64
    cd /some/where/here/lives/the/workspace
    export IPHONEOS_DEPLOYMENT_TARGET=9.3
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
      -arch x86_64
      -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.3.sdk
      -L/Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Products/Release-iphonesimulator
      -F/Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Products/Release-iphonesimulator
      -filelist /Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Intermediates/MyApp.build/Release-iphonesimulator/MyApp.build/Objects-normal/x86_64/MyApp.LinkFileList
      -Xlinker
      -rpath
      -Xlinker @executable_path/Frameworks
      -mios-simulator-version-min=9.3
      -Xlinker
      -objc_abi_version
      -Xlinker 2
      -fobjc-arc
      -fobjc-link-runtime
      -stdlib=libc++
      -framework MyFramework 
      -Xlinker
      -dependency_info
      -Xlinker /Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Intermediates/MyApp.build/Release-iphonesimulator/MyApp.build/Objects-normal/x86_64/MyApp_dependency_info.dat
      -o /Users/me/Library/Developer/Xcode/DerivedData/MyWorkspace-ahzqvfgoxbedpudjdhtqudgqzwba/Build/Intermediates/MyApp.build/Release-iphonesimulator/MyApp.build/Objects-normal/x86_64/MyApp

Undefined symbols for architecture x86_64:
  "SomeFancyFuncFromTheFramework()", referenced from:
      -[AppDelegate application:didFinishLaunchingWithOptions:] in AppDelegate.o

person Sea Coast of Tibet    schedule 22.07.2016    source источник
comment
Добавили ли вы зависимость сборки в цель приложения для первой сборки фреймворка?   -  person NSGod    schedule 22.07.2016
comment
NSGod, я пробовал это, но он показывает только одну строку - имя проекта приложения; ничего не нужно выбирать и ничего о фреймворках.   -  person Sea Coast of Tibet    schedule 22.07.2016
comment
Файл MyApp_dependency_info.dat (из последних аргументов -Xlinker) содержит ссылки как на MyFramework.framework/MyFramework.tbd, так и на MyFramework.framework/MyFramework, оба внутри .../Build/Products/Release-iphonesimulator/, насколько я могу судить (и FWIW).   -  person Sea Coast of Tibet    schedule 22.07.2016
comment
Что ж, это странно. Я весь день работаю над приложением для iOS, где я делаю именно это, и оно работает нормально, но теперь я только что создал 2 быстрых тестовых проекта, и, похоже, он не работает должным образом (я ничего не получаю в списке, как вы когда я пытаюсь добавить цель фреймворка в качестве зависимости)... Не уверен, что происходит....   -  person NSGod    schedule 22.07.2016
comment
NSGod, я действительно готов отредактировать файл проекта либо в текстовом редакторе, либо с помощью скрипта на основе xcodeproj, чтобы все заработало правильно. Если нет другого решения, стоит попробовать.   -  person Sea Coast of Tibet    schedule 23.07.2016
comment
Ладно, наконец-то заработало, хоть и пришлось немного потрудиться. Я несколько раз выходил из Xcode, и когда я снова открывал проект, все казалось немного лучше. Собираюсь начать снова с нуля, чтобы посмотреть, смогу ли я сделать это снова....   -  person NSGod    schedule 23.07.2016


Ответы (1)


Сначала создайте проект платформы iOS, обязательно задав параметру сборки Installation Directory (INSTALL_PATH) для цели платформы значение @rpath. Я бы изменил схему Xcode, чтобы сделать ее общей схемой. Теперь закройте проект фреймворка, чтобы убедиться, что его можно будет открыть, когда мы импортируем его в проект приложения, выполнив следующие шаги.

Затем создайте проект приложения iOS. Как и вы, я создал схему App (Debug) и схему App (Release). Я создал группу Frameworks в проекте приложения, как показано на рисунке ниже. Затем я нашел только что созданный файл .xcodeproj моего фреймворка и перетащил его в эту группу Frameworks. Откройте треугольники раскрытия, чтобы открыть Products каркасного проекта, как показано на изображении ниже. Перетащите его в раздел Embedded Binaries в разделе General целевого приложения. Это должно автоматически добавить другие шаги, которые вам нужно будет предпринять, чтобы заставить все работать правильно (я полагаю, что они включают добавление фреймворка в качестве зависимости, связывание с фреймворком и копирование фреймворка в построенное приложение).

введите здесь описание изображения

Последний шаг — убедиться, что фреймворк можно найти во время компиляции. В настройках сборки целевого приложения обязательно установите для Framework Search Paths (FRAMEWORK_SEARCH_PATHS) значение $(BUILT_PRODUCTS_DIR). Когда вы выбираете схему для приложения, построенного в стиле сборки "Разработка", платформа будет построена в том же стиле сборки в том же каталоге, что и само приложение.

person NSGod    schedule 22.07.2016
comment
NSGod, спасибо за ответ. Теперь все выглядит намного лучше — в файле проекта нет ссылок на Debug-iphonesimulator внутри, и в качестве бонуса нет необходимости в явном рабочем пространстве. Тем не менее, я все еще получаю те же проблемы со связыванием при переключении схемы приложения с отладки на выпуск. - person Sea Coast of Tibet; 24.07.2016
comment
Переключение схемы запуска фреймворка на Release не помогло, как ни странно. - person Sea Coast of Tibet; 24.07.2016
comment
Еще одно обновление: он работает с фиктивным фреймворком именно так, как вы описали. Копаем дальше, чтобы выяснить причину, по которой исходный фреймворк не работает. - person Sea Coast of Tibet; 25.07.2016
comment
Таким образом, нарушителем был GCC_SYMBOLS_PRIVATE_EXTERN = YES в выпуске xcconfig фреймворка. Спасибо за помощь, Марк. - person Sea Coast of Tibet; 25.07.2016