Как экспортировать "толстый" Cocoa Touch Framework (для симулятора и устройства)?
С Xcode 6 мы получаем возможность создавать собственные динамические Cocoa Frameworks
,
Потому что:
Симулятор еще использую
32-bit
библиотеканачиная с 1 июня 2015 г. обновления приложений, представленные в App Store, должны включать поддержку 64-разрядных систем и должны быть встроены в iOS 8 SDK ( developer.apple.com)
Мы должны сделать толстую библиотеку для запуска проекта на устройствах и симуляторах. т.е. поддерживает как 32, так и 64 бит в Frameworks.
Но я не нашел никаких руководств, как экспортировать универсальный толстый Framework для будущей интеграции с другими проектами (и поделиться этой библиотекой с кем-то).
Вот мои шаги для воспроизведения:
Задавать
ONLY_ACTIVE_ARCH=NO
вBuild Settings
Добавить поддержку
armv7 armv7s arm64 i386 x86_64
вArchitectures
(наверняка)
- Создайте Framework и откройте его в Finder:
- Добавить эту структуру в другой проект
Фактический результат:
Но, в конце концов, у меня все еще есть проблема с запуском проекта с этой платформой на устройствах и симуляторе одновременно
если я возьму рамки из
Debug-iphoneos
папка - работает на устройствах и выдает ошибку на симуляторах:ld: symbol(s) not found for architecture i386
xcrun lipo -info CoreActionSheetPicker
Архитектуры в толстом файле: CoreActionSheetPicker: armv7 armv7s arm64
если я возьму рамки из
Debug-iphonesimulator
папка - работает на симуляторах. и у меня есть ошибка на устройстве:ld: symbol(s) not found for architecture arm64
xcrun lipo -info CoreActionSheetPicker
Архитектуры в толстом файле: CoreActionSheetPicker: i386 x86_64
Итак, как создать динамический фреймворк, работающий на устройствах и симуляторах?
Этот ответ касался Xcode 6 iOS Создание Cocoa Touch Framework - проблемы с архитектурой, но они не повторяются.
Обновить:
Я нашел "грязный взлом" для этого случая. Смотрите мой ответ ниже. Если кто-то знает более удобный способ - пожалуйста, дайте мне знать!
6 ответов
Актуальность этого ответа: июль 2015 года. Скорее всего, все изменится.
TLDR;
В настоящее время XCode не имеет инструментов для автоматического экспорта универсальной толстой платформы, поэтому разработчик должен прибегнуть к ручному использованию lipo
инструмент. Также в соответствии с этим радаром перед отправкой в AppStore разработчик, который является потребителем фреймворка, также должен использовать lipo
соскоблить кусочки симулятора с каркаса.
Более длинный ответ следует
Я провел аналогичное исследование в теме (ссылка внизу ответа).
Я не нашел никакой официальной документации о распространении, поэтому мое исследование было основано на изучении форумов Apple Developer, проектов Carthage и Realm и моих собственных экспериментах с xcodebuild
, lipo
, codesign
инструменты.
Вот длинная цитата (с небольшой разметкой от меня) из ветки Apple Developer Forums Экспорт приложения со встроенной платформой:
Как правильно экспортировать фреймворк из фреймворкового проекта?
На данный момент единственным способом является именно то, что вы сделали:
- Постройте цель как для симулятора, так и для устройства iOS.
Перейдите в папку DerivedData Xcode для этого проекта и объедините два двоичных файла в единую структуру. Однако, когда вы создаете цель платформы в XCode, удостоверьтесь, что изменили настройку цели 'Build Active Architecture Only' на 'NO'. Это позволит Xcode построить цель для нескольких типов бинарников (arm64, armv7 и т. Д.). Вот почему он работает с XCode, но не как отдельный двоичный файл.
Также вы захотите убедиться, что схема настроена на сборку Release и построить целевую платформу против релиза. Если вы все еще получаете библиотеку с ошибкой загрузки, проверьте фрагменты кода в платформе.
- использование
lipo -info MyFramworkBinary
и изучить результат.
lipo -info MyFrameworkBinary
Результат
i386 x86_64 armv7 arm64
- Современные универсальные фреймворки будут включать 4 слайса, но могут включать больше:
i386 x86_64 armv7 arm64
Если вы не видите хотя бы 4, это может быть связано с настройкой Build Active Architecture.
Это описывает процесс почти так же, как это сделал @skywinder в своем ответе.
Вот как Карфаген использует липо, а Царство использует липо.
ВАЖНАЯ ИНФОРМАЦИЯ
Существует радар: Xcode 6.1.1 & 6.2: Платформы iOS, содержащие фрагменты симулятора, не могут быть отправлены в App Store, и долгое обсуждение вокруг этого по Realm#1163 и Carthage#188, которое закончилось специальным обходным решением:
перед отправкой в AppStore iOS Framework двоичные файлы должны быть удалены с фрагментов симулятора
Карфаген имеет специальный код: CopyFrameworks и соответствующий документ:
Этот скрипт работает вокруг ошибки отправки в App Store, вызванной универсальными двоичными файлами.
В Realm есть специальный скрипт: strip-frameworks.sh и соответствующий фрагмент документации:
Этот шаг необходим для обхода ошибки отправки в App Store при архивировании универсальных двоичных файлов.
Также есть хорошая статья: Удаление нежелательных архитектур из динамических библиотек в XCode.
Я сам использовал Realm's strip-frameworks.sh
который работал для меня отлично без каких-либо модификаций, хотя, конечно, любой может написать один с нуля.
Ссылка на мою тему, которую я рекомендую прочитать, потому что она содержит еще один аспект этого вопроса: подписывание кода - Создание фреймворков iOS/OSX: необходимо ли кодировать их перед распространением среди других разработчиков?
Это не очень понятное решение, но есть только один способ, который я нахожу:
Задавать
ONLY_ACTIVE_ARCH=NO
вBuild Settings
- Сборка библиотеки для симулятора
- Сборка библиотеки для устройства
Открыть в консоли
Products
папку для вашего фреймворка (вы можете открыть его, открыв папку фреймворка иcd ..
оттуда)
- Запустите этот скрипт из
Products
папка. Это создает толстый Framework в этой папке. (или сделайте это вручную, как описано ниже в 3. 4.)
Или же:
Объедините эти 2 фреймворка, используя липосакцию этим скриптом (замените
YourFrameworkName
на имя вашего фреймворка)lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
Замените новым двоичным файлом одну из существующих платформ:
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
- Прибыль:
./YourFrameworkName.framework
- готовый к использованию жирный бинарный файл! Вы можете импортировать его в свой проект!
Для проекта, которого нет в Workspaces:
Вы также можете попробовать использовать эту суть, как описано здесь. Но похоже, что это не работает для проектов в рабочих пространствах.
Ответ @Stainlav был очень полезен, но вместо этого я скомпилировал две версии фреймворка (одну для устройства и одну для симулятора), а затем добавил следующее Run Script Phase
для автоматического копирования предварительно скомпилированной среды, необходимой для работающей архитектуры
echo "Copying frameworks for architecture: $CURRENT_ARCH"
if [ "${CURRENT_ARCH}" = "x86_64" ] || [ "${CURRENT_ARCH}" = "i386" ]; then
cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi
Таким образом, я не пользуюсь lipo
чтобы создать толстую структуру ни царства strip-frameworks.sh
удалить ненужные фрагменты при отправке в App Store.
Я просто хочу обновить этот замечательный ответ @odm. Поскольку Xcode 10, CURRENT_ARCH
Переменная больше не отражает архитектуру сборки. Поэтому я изменил скрипт, чтобы проверить платформу:
echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi
Я также добавил строку, чтобы очистить целевой каталог перед копированием, поскольку заметил, что в противном случае дополнительные файлы в подкаталогах не будут перезаписаны.
В основном для этого я нашел очень хорошее решение. вам просто нужно следовать этим простым шагам.
- Создайте каркас касания какао.
- Установите битовый код включенным на номер
- Выберите вашу цель и выберите редактировать схемы. Выберите Run и выберите Release из вкладки Info.
- Никаких других настроек не требуется.
- Теперь создайте структуру для любого симулятора, поскольку симулятор работает на архитектуре x86.
- Нажмите на группу продуктов в Project Navigator и найдите файл.framework.
- Щелкните правой кнопкой мыши по нему и выберите Показать в поиске. Скопируйте и вставьте его в любую папку, лично я предпочитаю название "симулятор".
- Теперь создайте инфраструктуру для универсального устройства iOS и выполните шаги с 6 по 9. Просто переименуйте папку в "устройство" вместо "симулятор".
- Скопируйте файл устройства.framework и вставьте его в любой другой каталог. Я предпочитаю немедленный супер каталог обоих. Таким образом, структура каталогов теперь становится:
- рабочий стол
- устройство
- MyFramework.framework
- имитатор
- MyFramework.framework
- MyFramework.framework Теперь откройте терминал и перейдите на рабочий стол. Теперь начните вводить следующую команду:
lipo-создать 'устройство /MyFramework.framework/MyFramework' 'симулятор /MyFramework.framework/MyFramework' -output 'MyFramework.framework/MyFramework'
и это все. Здесь мы объединяем симулятор и версию устройства двоичного файла MyFramework, представленного внутри MyFramework.framework. Мы получаем универсальный фреймворк, который строится для всех архитектур, включая симулятор и устройство.
Мой ответ охватывает следующие пункты:
Сделать фреймворк, который работает как для симулятора, так и для устройства
Как экспортировать "толстый" Cocoa Touch Framework (для симулятора и устройства одновременно)?
Неопределенные символы для архитектуры x86_64
ld: символы не найдены для архитектуры x86_64
Шаги 1: сначала создайте свои фреймворки с помощью симулятора
Шаги 2: После успешного завершения процесса построения симулятора, теперь создайте для своей среды фреймворк с выбором целевого устройства или выбором универсального устройства iOS.
Шаг 3: Теперь выберите цель вашей платформы и для этого в разделе "Этапы сборки" выберите "Добавить сценарий запуска" и скопируйте приведенный ниже код сценария).
Шаг 4: Теперь, наконец, соберите заново, и ваш фреймворк готов к совместимости как с симулятором, так и с устройством. Ура!!!!
[Примечание: мы должны иметь обе совместимые рамки, готовые до последнего шага 4 (совместимы симулятор и архитектура устройства, если нет, пожалуйста, правильно выполните шаги 1 и 2 выше)
Смотрите контрольное изображение:
Поместите следующий код в область оболочки:
#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${BUILD_DIR}/${CONFIGURATION}-universal"