Как экспортировать "жир" Cocoa Touch Framework (для симулятора и устройства)?

С Xcode 6 мы получаем возможность создавать собственный динамический Cocoa Frameworks.

enter image description here

Из-за:

  • Симулятор по-прежнему использует библиотеку 32-bit

  • начиная с 1 июня 2015 г. Обновления приложений, представленные в App Store, должны включать поддержку 64-битной версии и быть построены с помощью SDK iOS 8 (developer.apple.com)

Мы должны сделать жировую библиотеку для запуска проекта на устройствах и симуляторах. то есть поддерживать 32 и 64 бит в Framework.

Но я не нашел никаких руководств, как экспортировать универсальную жировую структуру для дальнейшей интеграции с другими проектами (и поделиться этой библиотекой с кем-то).

Вот мои шаги для воспроизведения:

  • Установите ONLY_ACTIVE_ARCH=NO в Build Settings

    enter image description here

  • Добавьте поддержку armv7 armv7s arm64 i386 x86_64 в Architectures (точно)

enter image description here

  1. Построить структуру и открыть ее в Finder:

enter image description hereenter image description here

  1. Добавьте эту структуру в другой проект

Фактический результат:

Но в итоге у меня все еще есть проблема с запуском проекта с этой структурой на устройствах и симуляторе сразу.

  • если я беру фреймворк из папки 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 - проблемы с архитектурой, но он не дублируется.


Обновление:

Я нашел "грязный взлом" для этого случая. См. Мой ответ ниже. Если кто-то знает более удобный способ - пожалуйста, дайте мне знать!

Ответ 1

Действительность этого ответа: июль 2015 года. Скорее всего, все изменится.

TL;DR;

В настоящее время Xcode не имеет инструментов для автоматического экспорта универсальной жировой структуры, поэтому разработчик должен прибегнуть к ручному использованию инструмента lipo. Также в соответствии с этот радар перед представлением разработчику AppStore, являющемуся потребителем инфраструктуры, также должен использовать lipo для удаления срезов симулятора из фреймворка.

Более длинный ответ следует


Я сделал аналогичные исследования в теме (ссылка внизу ответа).

Я не нашел официальной документации о распределении, поэтому мои исследования были основаны на исследовании проектов Apple Developer, проектов Carthage и Realm и моих собственных экспериментов с инструментами xcodebuild, lipo, codesign.

Здесь длинная цитата (с небольшим разметкой от меня) от форума разработчиков Apple Экспорт приложения со встроенной инфраструктурой:

Каков правильный способ экспорта фреймворка из проекта framework?

В настоящее время единственный способ - это именно то, что вы сделали:

  • Создайте цель как для симулятора, так и для устройства iOS.
  • Перейдите в папку Xcode DerivedData для этого проекта и переместите два двоичных файла вместе в одну единую структуру. Однако, когда вы создаете целевую среду фреймворка в Xcode, не забудьте настроить целевой параметр "Build Active Architecture Only" на "NO". Это позволит Xcode строить цель для нескольких типов бинарти (arm64, armv7 и т.д.). Вот почему он работает с Xcode, но не как автономный двоичный файл.

  • Также вы захотите убедиться, что схема настроена на сборку Release и построит целевую среду framework для выпуска. Если вы все еще получаете ошибку, не загруженную библиотекой, проверьте фрагменты кода в фреймворке.

  • Используйте lipo -info MyFramworkBinary и просмотрите результат.

lipo -info MyFrameworkBinary

Результат i386 x86_64 armv7 arm64

  • Современные универсальные рамки будут включать в себя 4 среза, но могут включать в себя больше: i386 x86_64 armv7 arm64Если вы не видите по крайней мере этого 4, это связано с настройкой Build Active Architecture.

Это описывает процесс почти так же, как @skywinder сделал это в своем ответе.

Вот как Карфаген использует липо и Realm использует lipo.


ВАЖНАЯ ДЕТАЛИ

Существует радар: Xcode 6.1.1 и 6.2: рамки iOS, содержащие ломтики симулятора, не могут быть отправлены в App Store и длинными обсуждение вокруг него на Realm # 1163 и Карфаген # 188, который закончилась специальным обходом:

перед отправкой в ​​AppStore бинарные файлы инфраструктуры iOS должны быть удалены из ломтиков симулятора

У Карфагена есть специальный код: CopyFrameworks и соответствующий фрагмент документации:

Этот script работает вокруг Ошибка представления App Store, вызванного универсальными двоичными файлами.

В Realm есть специальный script: strip-frameworks.sh и соответствующий фрагмент документации:

Этот шаг необходим для работы с ошибкой представления Store Store при архивировании универсальных двоичных файлов.

Также есть хорошая статья: Удаление нежелательных архитектур из динамических библиотек в Xcode.

Я сам использовал Realm strip-frameworks.sh, который работал у меня совершенно без каких-либо изменений, хотя, конечно, любой может свободно писать с нуля.


Ссылка на мою тему, которую я рекомендую читать, потому что она содержит другой аспект этого вопроса: подписание кода - Создание iOS/OSX Framework: необходимо ли их кодовое кодирование перед распространением на другие разработчики?

Ответ 2

Это не столь ясное решение, но есть только способ, который я нахожу:

  • Установите ONLY_ACTIVE_ARCH=NO в Build Settings

    • Библиотека сборки для симулятора
    • Библиотека сборки для устройства
  • Откройте в консоли Products папку для вашей фреймворка (вы можете открыть ее через открытую папку фреймворка и cd .. оттуда)

enter image description hereenter image description here

  1. Запустите this script из Products. В этой папке создается fat Framework. (или сделайте это вручную, как описано ниже в разделе 3. 4.)

Или:

  1. Объедините эти 2 Framework с помощью lipo с помощью этого script (замените YourFrameworkName на ваше имя Framework)

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
    
  2. Замените новую двоичную одну из существующих фреймворков:

    cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
    mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
    

    1. Прибыль: ./YourFrameworkName.framework - - готовый к использованию жирный бинарный! Вы можете импортировать его в свой проект!

Для проекта это не в Workspaces:

Вы также можете попытаться использовать этот смысл, как описано здесь. Но кажется, что он не работает для проектов в рабочих пространствах.

Ответ 3

Ответ на

@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 для создания живого фрейма, а не для Realm strip-frameworks.sh для удаления ненужных фрагментов при отправке в App Store.

Ответ 4

в основном для этого я нашел очень хорошее решение. вам просто нужно выполнить эти простые шаги.

  • Создайте структуру cocoa touch.
  • Установить бит-код с номером.
  • Выберите цель и выберите схемы редактирования. Выберите "Выполнить" и выберите "Выйти из вкладки" Информация ".
  • Никакой другой настройки не требуется.
  • Теперь создадим фреймворк для любого симулятора, поскольку симулятор работает на архитектуре x86.
  • Выберите группу продуктов в Навигаторе проектов и найдите файл .framework.
  • Щелкните правой кнопкой мыши по нему и нажмите "Показать в поиске". Скопируйте и вставьте его в любую папку, я лично предпочитаю имя "симулятор".
  • Теперь создадим структуру для универсального устройства iOS и следуйте инструкциям с 6 по 9. Просто переименуйте папку в "устройство" вместо "симулятора".
  • Скопируйте файл .framework и вставьте его в любой другой каталог. Я предпочитаю немедленный супер-каталог обоих. Таким образом, структура каталогов теперь становится:
    • Desktop
    • Устройство
      • MyFramework.framework
    • Тренажер
      • MyFramework.framework
    • MyFramework.framework Теперь откройте терминал и cd на рабочем столе. Теперь начните вводить следующую команду:

lipo -create 'device/MyFramework.framework/MyFramework' 'simulator/MyFramework.framework/MyFramework' -output 'MyFramework.framework/MyFramework

и что он. Здесь мы объединяем симулятор и версию устройства двоичного файла MyFramework, присутствующего в MyFramework.framework. Мы получаем универсальную структуру, которая строит для всех архитектур, включая симулятор и устройство.

Ответ 5

Мой ответ охватывает следующие пункты:

  • Создайте фреймворк, который работает как для симулятора, так и для устройства

  • Как экспортировать "жир" Cocoa Touch Framework (для Simulator и устройства оба)?

  • Undefined символы для архитектуры x86_64

  • ld: символы (символы), не найденные для архитектуры x86_64

Шаги 1: сначала создайте свои фреймворки с помощью цели Simulator

Шаги 2: После успеха процесса сборки симулятора теперь создайте для своей рамки с выбором целевого устройства или универсальным выбором устройства iOS

Шаг 3: Теперь выберите целевую среду фрейма и для этого. В разделе "Фазы сборки" выберите "Добавить запуск Script" и скопируйте приведенный ниже код script)

Шаг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 directory

cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"


# Step 6. Convenience step to open the project directory in Finder

open "${BUILD_DIR}/${CONFIGURATION}-universal"