如何导出“胖”cocoa触摸框架(模拟器和设备)?

使用Xcode 6,我们可以创build自己的Dynamic Cocoa Frameworks

在这里输入图像描述

因为:

  • 模拟器仍然使用32-bit

  • 从2015年6月1日开始,提交给App Store的应用更新必须包含64位支持,并使用iOS 8 SDK( developer.apple.com )

我们必须让胖库运行在设备和模拟器上的项目。 即在Frameworks中同时支持32位和64位。

但是我没有find任何手册,如何导出通用胖框架,以便将来与其他项目集成(并与某人分享这个库)。

这是我重现的步骤:

  1. 在“ Build Settings设置ONLY_ACTIVE_ARCH=NO

    在这里输入图像描述

  2. 添加支持armv7 armv7s arm64 i386 x86_64Architectures (当然)

在这里输入图像描述

  1. 构build框架并在Finder中打开它:

在这里输入图像描述在这里输入图像描述

  1. 将此框架添加到另一个项目

实际结果:

但是最终我仍然在设备和模拟器上一起运行带有这个框架的项目的问题。

  • 如果我从Debug-iphoneos文件夹中获取框架 – 它在设备上工作并且在模拟器上出错: ld: symbol(s) not found for architecture i386

     xcrun lipo -info CoreActionSheetPicker 

    fat文件中的体系结构:CoreActionSheetPicker是:armv7 armv7s arm64

  • 如果我从Debug-iphonesimulator文件夹中获取框架 – 它可以在模拟器上运行。 和我的设备上有错误: ld: symbol(s) not found for architecture arm64

     xcrun lipo -info CoreActionSheetPicker 

    胖文件中的体系结构:CoreActionSheetPicker是:i386 x86_64

那么,如何创build一个适用于设备和模拟器的dynamic框架呢?

这个答案与Xcode 6相关iOS创buildCocoa Touch框架 – 架构问题,但它不是重复的。


更新:

我发现这个案子“肮脏的黑客”。 看到我的答案在下面 。 如果有人知道更方便的方式 – 请让我知道!

这个答案的实际情况是:2015年7月。事情很可能会改变。

TLDR;

目前Xcode没有自动导出通用脂肪框架的工具,所以开发者必须诉诸手动使用lipo工具。 另外根据这个雷达提交给AppStore的开发者是框架的用户也必须使用lipo从框架中lipo模拟器片。

较长的答案如下


我在主题上做了类似的研究(答案底部的链接)。

我还没有find关于发行的官方文档,所以我的研究是基于对苹果开发者论坛,迦太基和领域项目的探索,以及我对xcodebuildlipocodesign工具的实验。

这里是从苹果开发者论坛线程长引文(与我一点点标记) 导出与embedded式框架的应用程序 :

从框架项目中导出框架的正确方法是什么?

目前唯一的方法就是你所做的:

  • 构build模拟器和iOS设备的目标。
  • 导航到该项目的Xcode的DerivedData文件夹,并将两个二进制文件合并成一个单一的框架。 但是,当您在Xcode中构build框架目标时,请确保将目标设置“仅构build主动架构”调整为“否”。 这将允许Xcode构build多个binartytypes(arm64,armv7等)的目标。 这就是为什么它从Xcode的作品,而不是作为一个独立的二进制文件。

  • 此外,您还需要确保该scheme设置为发布版本,并针对版本构build框架目标。 如果你仍然得到一个没有加载错误的库,请检查框架中的代码片。

  • 使用lipo -info MyFramworkBinary并检查结果。

lipo -info MyFrameworkBinary

结果是i386 x86_64 armv7 arm64

  • 现代通用框架将包括4个切片,但可能包括更多: i386 x86_64 armv7 arm64如果您没有看到至less这4个,它是由于构build主动架构设置。

这个描述的过程几乎和@skywinder在他的回答中一样。

这是迦太基如何使用lipo和Realm使用lipo 。


重要细节

有雷达: Xcode 6.1.1和6.2:包含模拟器切片的iOS框架不能提交给App Store,并且在Realm#1163和Carthage#188上进行了长时间的讨论,结果是特殊的解决方法:

在提交到AppStore之前,iOS框架二进制文件必须从模拟器片剥离

迦太基有特殊的代码: CopyFrameworks和相应的文件:

此脚本解决了由通用二进制文件触发的App Store提交错误 。

领域有特殊的脚本: strip-frameworks.sh和相应的文档:

归档通用二进制文件时,需要执行此步骤来解决App Store提交错误 。

另外还有一篇好文章: 从Xcode中的dynamic库中剥离不需要的体系结构 。

我自己使用了Realm的strip-frameworks.sh ,它完全为我工作,没有任何修改,当然任何人都可以自由地从头开始编写一个。


链接到我的主题,我推荐阅读,因为它包含了这个问题的另一个方面:代码签名 – 创buildiOS / OSX框架:是否有必要在分发给其他开发人员之前进行编码?

这不是很清楚的解决办法,但是有办法,我发现:

  1. 在“ Build Settings设置ONLY_ACTIVE_ARCH=NO

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

在这里输入图像描述在这里输入图像描述

  1. 从“ Products文件夹运行脚本。 它在这个文件夹中创build一个胖框架。 (或者手动完成,如3.4中所述

要么:

  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准备使用的胖二进制! 您可以将其导入到您的项目!

对于不在工作区中的项目:

您也可以尝试使用此处所述的要点 。 但它似乎并不适用于工作区中的项目。

@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来创build一个胖框架,而不是Realm的strip-frameworks.sh来提交到App Store时删除不必要的切片。

基本上这个我find了很好的解决scheme。 你只需要遵循这些简单的步骤。

  1. 创build一个cocoa触摸框架。
  2. 将位代码设置为“否”
  3. select您的目标并select编辑scheme。 select运行并select从信息选项卡释放。
  4. 没有其他设置要求。
  5. 现在为模拟器在x86架构上运行构build任何模拟器的框架。
  6. 点击Project Navigator中的Products组,find.framework文件。
  7. 右键单击它,然后单击查找器中显示。 复制并粘贴到任何文件夹,我个人更喜欢“模拟器”的名称。
  8. 现在构build通用iOS设备的框架,并按照步骤6到9.只需将文件夹重命名为“设备”,而不是“模拟器”。
  9. 复制设备.framework文件并粘贴到其他目录中。 我更喜欢两个直接的超级目录。 所以目录结构现在变成:
    • 桌面
    • 设备
      • MyFramework.framework
    • 模拟器
      • MyFramework.framework
    • MyFramework.framework现在打开terminal并cd到桌面。 现在开始input以下命令:

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

就是这样。 在这里我们合并MyFramework.framework中的模拟器和设备版本的MyFramework二进制文件。 我们得到一个通用的框架,为所有的架构,包括模拟器和设备。

我的答案涵盖以下几点:

  • 制作适用于模拟器和设备的框架

  • 如何导出“胖”cocoa触摸框架(模拟器和设备都)?

  • 架构x86_64的未定义符号

  • ld:找不到架构x86_64的符号

步骤1:首先用模拟器目标构build您的框架

步骤2:模拟器构build过程成功后,现在为您的框架构build设备目标select或通用iOS设备select

第3步:现在select您的框架目标,并在“构build阶段”select“添加运行脚本”,并复制下面的脚本代码)

第4步:现在最后再次构build,你的框架已经准备好兼容模拟器和设备。 欢呼!!!!

[注意:在最后一步4之前,我们必须准备兼容的框架(模拟器和设备体系结构兼容,如果不正确,请按照上面的步骤1和步骤2)

查看参考图片:

在这里输入图像描述

在这里输入图像描述

把下面的代码放到shell区域:

 #!/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"