Xcode 6 iOS Создание Cocoa Touch Framework - проблемы с архитектурой

Я пытаюсь создать динамическую структуру для приложения iOS. Благодаря новой версии Xcode (6) мы можем выбрать Cocoa Touch Framework, когда мы создадим новый проект, и больше не нужно добавлять агрегированную цель, запустите script и так сделать ее. У меня нет проблем при создании фреймворка. Но когда я пытаюсь использовать его в приложении iOS, я получаю некоторые проблемы с архитектурой.

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture armv7:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Ну, я попытался изменить настройки проекта и целевого объекта фреймворка (Архитектуры и Создать только допустимую архитектуру и Действительные архитектуры). Я сделал то же самое для проекта приложения iOS, но ничего не работает. Я думаю, что я чего-то не понял.

Например, когда я создаю фреймворк только для i386 (iOS Simulator), проверьте с помощью командной строки "xcrun lipo -info MyFramework", у меня есть проблема, которая

ld: предупреждение: игнорирование файла /Library/Frameworks/MyFramework.framework/MyFramework, файл был создан для x86_64, который не связан с архитектурой (i386)...

Если кто-то может помочь мне получить фреймворк, который работает для всех архитектур iOS, включая симуляторы.

Ответ 1

На основе всех ответов post на raywenderlich.com и gist, созданный Крис Конвей Я придумал this.

Выполняя следующие шаги, я смог создать структуру Cocoa Touch (включая файлы Swift и Objective-C), которая содержит все архитектуры как для симулятора, так и для устройства:

  • Создайте новую (агрегированную) цель в своем проекте структуры
  • В разделе "Фазы сборки" выберите "Добавить запуск Script" и скопируйте содержимое этот файл
  • Выберите цель Совокупная цель в раскрывающемся списке Схема
  • Создать целевую для агрегатной схемы

Надеюсь, это поможет:)

UPDATE: Исправлена ​​ошибка в сущности, где пути на шаге 3 были неверными. Благодаря Tokuriku!!

ОБНОВЛЕНИЕ. В Xcode 7 и 8 нажмите "Файл" > "Создать" > "Цель..." и выберите "Другая", чтобы выбрать "Сгруппировать цель"

Ответ 2

Попробуйте выполнить следующие шаги, чтобы создать рабочую область, содержащую проект рамки и проект приложения.

Workspace:

  • Создайте рабочее пространство.

Рамочный проект:

  • Создайте проект iOS Cocoa touch Framework внутри рабочей области.
  • Добавьте простой класс Objective C MyClass (заголовок .h и файл реализации .m) и создайте приветствие метода - (void).
  • Go project Фазы сборки > Заголовки > Переместите MyClass.h из Project в Общие.
  • Измените схему на проект рамки и выберите iOS simulator, а затем выполните. (Выберите iOS Device, если приложение, интегрирующее эту инфраструктуру, запускается на устройстве. Я буду продолжать использовать симулятор в этом примере)
  • У вас не должно возникнуть проблемы, сборка фреймов находится в каталоге Derived Data​​strong > , который вы можете найти в Организаторе.

Проект приложения:

  • Создайте приложение Swift Single View внутри рабочей области.
  • Перетащите выше рамки фреймворка iOS (найдено в Debug-iphonesimulator или Release-iphonesimulator) в ваш проект.
  • Создайте заголовок для моста, чтобы открыть методы класса Objective C для Swift.
  • Импортируйте MyClass.h в сборке заголовочного файла.
  • Обратите внимание, что если определение MyClass не найдено, добавьте путь структуры Заголовки для создания настроек Контуры поиска заголовков.
  • Создайте экземпляр MyClass в viewDidLoad из ViewController.swift, затем вызовите приветствия.
  • Добавить фреймворк в цель > Встроенные двоичные файлы
  • Измените схему на проект и выберите iOS симулятор, затем создайте.
  • Вы должны иметь возможность видеть приветственные сообщения.

Обратите внимание, что в приведенном выше примере показано, как создать приложение, работающее в симуляторе. Если вам нужно создать универсальную статическую библиотеку, которая работает как на симуляторе, так и на устройствах, тогда общие шаги:

  • Библиотека сборки для симулятора
  • Библиотека сборки для устройства
  • Объедините их с помощью lipo

В Интернете есть хорошие ссылки, здесь.

Создайте универсальный двоичный файл для фреймворка: перейдите в каталог Derived Data, затем /Build/Products, следующая команда должна помочь вам создать универсальный двоичный файл в каталоге Продукты:

lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01" 

Обратите внимание, что framework-test-01 - это мое имя проекта фрейма.

Ответ 3

Ниже приведены шаги по созданию жирной (универсальной) структуры:

  • Установите ONLY_ACTIVE_ARCH=NO в Build Settings в вашем проекте.

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

enter image description hereenter image description here

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

    framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \
    cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \
    lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name"
    

Или:

  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 - - готовый к использованию жирный бинарный!. Вы можете импортировать его в свой проект!

Для проекта это не в xcworkspace -es:

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

Ответ 4

То, как я это делал, похоже на vladof, но, надеюсь, немного проще. Я сделал структуру подпроектом проекта приложения.

Рамочный проект

  • Создайте новую iOS Cocoa Touch Framework. Назовите это MyLib. Это создаст один MyLib.h
  • Добавьте простой класс Cocoa Touch Obj-C, MyClass (.h и .m) и в реализацию .m, создайте метод, который возвращает строку, - приветствия (NSString *);
  • В MyLib.h добавьте это внизу, #import "MyClass.h"
  • В целевом разделе "Сборка фаз/заголовков" переместите MyClass.h из раздела "Проект" в раздел "Публикация".
  • Сделайте сборку (cmd-B)
  • Закройте проект

Проект приложения

  • Создайте новый проект приложения Single View, будь то Swift или Obj-C. Назовите это MyApp.
  • Из Finder перетащите файл проекта MyLib в раздел органайзера левой руки окна MyApp и убедитесь, что строка вставки находится чуть ниже MyApp. Это делает MyLib подпроектом MyApp. (Его можно по-прежнему использовать в других проектах)
  • Нажмите на MyApp в организаторе, а затем выберите цель MyApp и выберите "Сформировать фазы".
  • В целевых зависимостях щелкните знак + и добавьте MyLib.
  • В Link with Libraries щелкните знак + и добавьте MyLib.framework.

Для приложения Obj-C

  • В ViewController.m добавьте #import
  • В viewDidLoad добавьте следующие строки:
  • MyLib * x = [[MyLib alloc] init];
  • NSLog (@ "% @", x.greetings);
  • Запустите проект, и вы увидите сообщение в окне отладки. -

Для приложения Swift

  • В ViewController.swift добавьте импорт MyLib
  • в viewDidLoad, добавьте следующие строки:
  • var x: MyLib = MyLib()
  • println ( "(x.greetings())" ) -

Таким образом, приложение зависит от фреймворка, поэтому, если вы вносите изменения в классы инфраструктуры, вам не нужно изменять цели для создания структуры отдельно, она сначала компилирует структуру, затем приложение.

Ответ 5

Я немного изменил кого-то script для поддержки всех архитектур Simulator:

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}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. 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 4. Convenience step to copy the framework to the project directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"

# Step 5. Delete temporary build directory in the project directory
rm -rf "${PROJECT_DIR}/build"

# Step 6. Convenience step to open the project directory in Finder
open "${PROJECT_DIR}"

Ответ 7

Наконец, я заработал у меня! И жаль большую желтую рамку, я понятия не имею, как ее лучше отформатировать.

Решение было получено от Claudio Romandi, но связанный с ним script имеет небольшую проблему. Я не могу комментировать его сообщение, потому что мне нужна репутация 50, поэтому мне остался без выбора, но чтобы скопировать его сообщение, чтобы иметь полное решение.

  • Создайте новую (совокупную) цель в своем проекте Framework
  • Выберите агрегат в рабочей области и добавьте "New Run script Phase"
  • Вставьте в него следующий код:

    #!/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) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
    
    # 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 "${PROJECT_DIR}"
    
  • Выберите "Агрегат в выпадающем списке схем"

  • Сборка, все готово!

Проблема заключалась в том, что каталог симулятора указывал на несуществующий каталог, меняя "Framework" на "$ {PROJECT_NAME}" в 2-х местах, сделал трюк:)

Ответ 8

Несколько дополнительных точек вокруг подхода, совместно используемого vladof, которые более применимы к быстродействующим платформам

  • script в связанной ссылке требуется модификация для копирования всех файлов из iphonesimulator и iphoneos, так как у swift есть отдельные скомпилированные файлы для arm и i386
  • Убедитесь, что у вас есть ARCHS = "x86_64" ONLY_ACTIVE_ARCH = НЕТ в сборке для iphonesimulator, чтобы избежать проблем с компоновщиками для симулятора
  • Убедитесь, что ваш интерфейс/класс расширяет NSObject, иначе вы столкнетесь с проблемами при попытке использовать код в swift (он будет жаловаться на невозможность создания объекта using().