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文件):
- 在您的框架的项目中创build一个新的(聚合)目标
- 在“构build阶段”下,select“添加运行脚本”并复制此文件的内容
- 在Scheme Selection下拉菜单中select Aggregate target
- 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-iphonesimulator或Release-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胖(通用)框架的步骤:
-
在项目的“
Build Settings
中设置ONLY_ACTIVE_ARCH=NO
。 -
- build立模拟器库
- 为设备构build库
-
在您的框架的控制台
Products
文件夹中打开(您可以通过打开的框架文件夹和cd ..
打开它)
-
从“
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"
要么:
-
通过这个脚本使用lipo结合这两个框架(将
YourFrameworkName
replace为您的框架名称)lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
-
用新的二进制replace现有的框架之一:
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
- 利润:
./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。
- 在Target 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..
- 在您的框架项目中创build一个新的(聚合)目标
- select工作区中的聚合并添加一个“新build运行脚本阶段”
-
把下面的代码放在里面:
#!/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}"
-
在schemeselect下拉列表中select聚合
- build立,你完成了!
问题是,模拟器目录指向一个不存在的目录,在2个地方更改“框架”为“$ {PROJECT_NAME}”诀窍:)
vladof共享的方法还有一些附加点更适用于基于Swift的框架
- 相关链接中的脚本需要修改以复制来自iphonesimulator和iphoneos的所有文件,因为swift为arm和i386分别编译了文件
- 确保在iphonesimulator的版本中有ARCHS =“x86_64”ONLY_ACTIVE_ARCH = NO,以避免模拟器的链接器问题
- 确保你的接口/类扩展NSObject,否则当你尝试在swift中使用代码时会碰到问题(它会抱怨使用()不能创build对象。