Xcode 6 iOS创build一个Cocoa Touch框架 – 体系结构问题

我正在尝试为iOS应用程序制作一个dynamic框架。 感谢Xcode(6)的新版本,当我们创build一个新项目时,我们可以select一个Cocoa Touch框架,并且不再需要添加一个聚合目标,运行脚本等等。 当我构build框架时,我没有任何问题。 但是当我试图在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) 

那么我试图改变框架项目和目标的设置(架构和build立有效的架构只有有效的体系结构)。 我为iOS应用程序项目做了同样的事情,但没有任何工作。 我觉得有一些我不明白的地方。

例如,当我构build只有i386(iOS模拟器)的框架检查命令行“xcrun lipo -info MyFramework”,我有一个问题

ld:warning:忽略文件/Library/Frameworks/MyFramework.framework/MyFramework,文件是为x86_64构build的,而不是被链接的架构(i386)…

如果有人能帮助我得到一个适用于包括模拟器在内的所有iOS架构的框架。

基于所有的回应, raywenderlich.com上的post和Chris Conway创造的要点提出了这个问题 。

执行以下步骤我能够构build包含模拟器和设备的所有体系结构的Cocoa Touch框架(包括Swift和Objective-C文件):

  1. 在您的框架的项目中创build一个新的(聚合)目标
  2. 在“构build阶段”下,select“添加运行脚本”并复制此文件的内容
  3. Scheme Selection下拉菜单中select Aggregate target
  4. build立 总体scheme目标

希望能帮助到你 :)

更新:修复了步骤#3中的path不正确的要点中的错误。 感谢Tokuriku !

更新在Xcode 7和8中,单击文件>新build>目标…,然后select“其他”组以select聚合目标

尝试以下步骤来创build一个包含框架项目和应用程序项目的工作区。

工作区:

  • 创build一个工作区。

框架项目:

  • 在Workspace中创build一个iOS Cocoa touch Framework项目。
  • 添加一个简单的Objective C类MyClass (头文件.h和实现文件.m),并创build一个方法– (void)问候语
  • 转到项目构build阶段 > 标题 >将MyClass.h项目移动到公共
  • 将scheme更改为框架项目并selectiOS模拟器 ,然后构build。 (如果集成此框架的应用程序在设备上运行,请select“ iOS设备” 。本例中我将继续使用模拟器)
  • 您应该没有问题构build,框架构build可以在您的派生数据目录中find,您可以在pipe理器中find它。

应用项目:

  • 在Workspace中创build一个Swift Single View应用程序。
  • 将iOS模拟器框架构build(在Debug-iphonesimulatorRelease-iphonesimulator中find拖到您的项目中。
  • 创build一个桥接头,将Objective C类的方法暴露给Swift。
  • 在桥接头文件中导入MyClass.h。
  • 请注意,如果找不到MyClass定义,那么添加构build设置标题searchpath的框架标题 path
  • ViewController.swift的 viewDidLoad中创buildMyClass的实例,然后调用问候语
  • 将框架添加到目标>embedded式二进制文件
  • 改变scheme到应用程序项目,并selectiOS模拟器 ,然后build立。
  • 你应该可以看到问候消息。

请注意,上面的例子演示了如何构build一个在模拟器中运行的应用程序。 如果您需要创build在模拟器设备上运行的通用静态库,那么一般的步骤是:

  • build立模拟器
  • 设备构build库
  • 结合他们使用lipo

网上有很多关于它的参考资料,例如。

为框架创build通用二进制文件:定位到Derived Data目录然后/ Build / Products ,以下命令应该帮助您在Products目录中创build通用二进制文件:

 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是我的框架项目名称。

下面是创build胖(通用)框架的步骤:

  1. 在项目的“ Build Settings中设置ONLY_ACTIVE_ARCH=NO

    • build立模拟器库
    • 为设备构build库
  2. 在您的框架的控制台Products文件夹中打开(您可以通过打开的框架文件夹和cd ..打开它)

在这里输入图像说明在这里输入图像说明

  1. 从“ Products文件夹运行此脚本 。 它在这个文件夹中创build一个胖框架。 (或者按照下面的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. 通过这个脚本使用lipo结合这两个框架(将YourFrameworkNamereplace为您的框架名称)

     lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName" 
  2. 用新的二进制replace现有的框架之一:

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

  1. 利润: ./YourFrameworkName.framework准备使用的胖二进制! 您可以将其导入到您的项目!

对于项目,不在xcworkspace -es中:

您也可以尝试使用这个要点但似乎它不适用于工作区中的项目。

我这样做的方式类似于vladof,但希望稍微简单一些。 我将该框架作为应用程序项目的一个子项目。

框架项目

  • 创build一个新的iOS Cocoa Touch框架。 称之为MyLib。 这将创build一个MyLib.h
  • 添加一个简单的Cocoa Touch Obj-C类,MyClass(.h​​&.m)并在执行.m中创build一个方法,返回一个string – (NSString *)问候语;
  • 在MyLib.h中,在底部附近添加#import“MyClass.h”
  • 在目标的“构build阶段/标题”部分中,将“项目”部分中的“MyClass.h”移动到“公开”部分。
  • 做生成(cmd-B)
  • closures该项目

应用程序项目

  • 创build一个新的单视图应用程序项目,Swift或Obj-C。 叫它MyApp。
  • 从Finder中,将MyLib项目文件拖到MyApp窗口的左边组织器部分,并确保插入线位于MyApp下方。 这使得MyLib成为MyApp的一个子项目。 (在其他项目中仍可以使用相同的方式)
  • 在pipe理器中点击MyApp,然后selectMyApp目标并selectBuild Phases。
  • 在Tar​​get Dependancies中,单击+号并添加MyLib。
  • 在链接库中,单击+号并添加MyLib.framework。

对于一个Obj-C应用程序

  • 在ViewController.m中,添加#import
  • 在viewDidLoad中,添加以下几行:
  • MyLib * x = [[MyLib alloc] init];
  • NSLog(@“%@”,x.greetings);
  • 运行该项目,您应该在debugging窗口中看到消息。 –

对于一个Swift应用程序

  • 在ViewController.swift中,添加import MyLib
  • 在viewDidLoad中,添加以下行:
  • var x:MyLib = MyLib()
  • println(“(x.greetings())”) –

通过这样做,应用程序依赖于框架,所以如果您在框架类中进行更改,则不必单独更改目标来构build框架,只需先编译框架,然后再编译应用程序。

我已经改变了某人的脚本来支持所有的模拟器的架构:

 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's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 5. Delete temporary build directory in the project's directory rm -rf "${PROJECT_DIR}/build" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 

一步一步的文章关于创buildcocoa触摸框架与在这个链接find的屏幕截图 – > 如何创buildcocoa触摸框架

最后,我得到它为我工作! 对于黄色的大框架感到抱歉,我不知道如何更好地格式化它。

解决scheme来自Claudio Romandi,但脚本链接有一个小问题。 我不能评论他的职位,因为我需要50的声誉,所以我没有select,只能复制他的职位,有一个完整的解决scheme..

  1. 在您的框架项目中创build一个新的(聚合)目标
  2. select工作区中的聚合并添加一个“新build运行脚本阶段”
  3. 把下面的代码放在里面:

     #!/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's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 
  4. 在schemeselect下拉列表中select聚合

  5. build立,你完成了!

问题是,模拟器目录指向一个不存在的目录,在2个地方更改“框架”为“$ {PROJECT_NAME}”诀窍:)

vladof共享的方法还有一些附加点更适用于基于Swift的框架

  1. 相关链接中的脚本需要修改以复制来自iphonesimulator和iphoneos的所有文件,因为swift为arm和i386分别编译了文件
  2. 确保在iphonesimulator的版本中有ARCHS =“x86_64”ONLY_ACTIVE_ARCH = NO,以避免模拟器的链接器问题
  3. 确保你的接口/类扩展NSObject,否则当你尝试在swift中使用代码时会碰到问题(它会抱怨使用()不能创build对象。