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


107

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

在此处输入图片说明

因为:

  • 模拟器仍在使用32-bit

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

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

但是我没有找到任何手册,没有找到如何导出通用的Fat Framework以便将来与其他项目集成(以及与他人共享该库)的手册。

这是我复制的步骤:

  1. 设置ONLY_ACTIVE_ARCH=NOBuild Settings

    在此处输入图片说明

  2. armv7 armv7s arm64 i386 x86_64Architectures(肯定)添加支持

在此处输入图片说明

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

在此处输入图片说明 在此处输入图片说明

  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框架-体系结构问题有关,但不是重复的。


更新:

我发现了这种情况下的“肮脏骇客”。请参阅下面的答案。如果有人知道更方便的方法-请让我知道!



@AndriusSteponavičius这个问题在2个月前被问到。
skywinder

是的,但是我想用户应该知道更多详细的答案
AndriusSteponavičius15年

在“构建设置”中设置ONLY_ACTIVE_ARCH = NO是重要的步骤。
Jedidja

如果您想在模拟器上运行它,则即使您的计算机具有64位体系结构,您的框架也需要在胖二进制文件中同时包含i386 x86_64切片!得知那艰难的路。
J.beenie'5

Answers:


82

答案的现实是:2015年7月。情况很可能会改变。

TLDR;

当前Xcode没有自动导出通用fat框架的工具,因此开发人员必须诉诸于手动使用lipo工具。同样根据此雷达,在提交给作为框架使用者的AppStore开发人员之前,还必须使用lipo它从框架中剥离模拟器片段。

答案更长


我对该主题(答案底部的链接)进行了类似的研究。

我还没有发现有关的,所以我的研究是基于对苹果开发者论坛,迦太基和领域的项目和我自己的实验探索分布的任何正式文件xcodebuildlipocodesign工具。

这是来自Apple Developer Forums线程具有嵌入式框架的App的长报价(带有一些标记):

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

当前唯一的方法就是您所做的:

  • 为模拟器和iOS设备构建目标。
  • 导航到该项目的Xcode的DerivedData文件夹,并将两个二进制文件一起封装到一个框架中。但是,在Xcode中构建框架目标时,请确保将目标设置“仅构建活动架构”调整为“否”。这将允许Xcode为多种binarty类型(arm64,armv7等)构建目标。这就是为什么它可以在Xcode上运行但不能作为独立的二进制文件运行的原因。

  • 另外,您还需要确保将方案设置为Release版本,并针对release构建框架目标。如果仍然出现库未加载错误,请检查框架中的代码片。

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

lipo -info MyFrameworkBinary

结果是 i386 x86_64 armv7 arm64

  • 现代通用框架将包括4个部分,但可能包括更多部分:i386 x86_64 armv7 arm64 如果您至少看不到这4个部分,则可能是由于“构建活动体系结构”设置所致。

这与@skywinder在回答中所做的过程几乎相同。

这就是迦太基使用lipoRealm使用lipo的方式


重要细节

有雷达:Xcode 6.1.1和6.2:不能将包含模拟器切片的iOS框架提交给App Store,有关Realm#1163Carthage#188的长时间讨论都已提交,最终以特殊的解决方法结束:

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

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

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

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

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

也有一篇不错的文章:从Xcode中的动态库中删除不需要的体系结构

我本人使用Realm strip-frameworks.sh,它无需任何修改即可完美地为我工作,尽管任何人都可以从头开始编写。


我建议阅读指向我的主题的链接,因为它包含此问题的另一个方面:代码签名- 创建iOS / OSX框架:在分发给其他开发人员之前是否有必要对其进行代码签名


1
我使用了lipo,但是当框架在模拟器中构建时,它显示带有类名的未解析标识符,但在设备中它可以工作。如果使用二进制的模拟器版本,那么它正在工作..任何想法?
苏西姆·萨曼塔

2
我没有发现任何证据证明Xcode 8.2在2016年12月对此有所改变。:/
Geoffrey Wiseman,

1
@Geoffrey,这在Xcode 9.2中有所改变还是有所不同?这是我第一次创建一个用于分发的二进制框架,我已经很害怕……
ScottyB,

遗憾的是,还没有做到这一点-不能说。祝好运。
杰弗里·怀斯曼

57

这不是很明确的解决方案,但是我发现只有办法:

  1. 设置ONLY_ACTIVE_ARCH=NOBuild Settings

    • 建立模拟器库
    • 设备的构建库
  2. Products您的框架的控制台文件夹中 打开(您可以通过打开框架文件夹并cd ..从那里打开它)

在此处输入图片说明 在此处输入图片说明

  1. 从文件夹运行脚本Products。它在此文件夹中创建胖Framework。(或按照下面3. 4.中的说明手动进行

要么:

  1. 通过此脚本使用lipo组合这两个Framework (替换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- 即用型脂肪二进制文件!您可以将其导入到您的项目中!

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

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


我以为苹果不再接受胖二进制文件了。kodmunki.wordpress.com/2015/03/04/...
Monstieur

1
@skywinder您是否找到其他任何简单的方法来导出Cocoa Touch Framework以准备使用胖二进制文件?我正在使用与上述相同的方法,但我不喜欢它。Xcode应该有一些可以使过程自动化的工具。
dev gr

1
@devgr还没有..这就是为什么我不接受自己的答案。仍在寻找更好的解决方案。
skywinder

1
无法在模拟器中运行,但可以在具有3个步骤和4个步骤的设备中使用
jose920405,2013年

1
@谁能解释为什么只使用Debug-文件夹lipo -create?可以将此框架用于Release配置吗?为什么?谢谢。
Yevhen Dubinin

10

@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

这样,我lipostrip-frameworks.sh无需创建胖框架,也无需在提交到App Store时通过Realm 删除不必要的内容。


您链接到哪一个?
加卡·詹察(JakaJančar)'16

@JakaJančar我链接到${SRCROOT}/Frameworks/Active文件夹中的链接。在编译时,它们将替换为活动体系结构的正确的预编译框架。
odm

2
爱它!这比“合并然后撕裂” lipo方法要简单得多。
clozach

2

基本上为此,我找到了很好的解决方案。您只需要遵循以下简单步骤。

  1. 创建一个可可触摸框架。
  2. 将启用的位码设置为“否”。
  3. 选择目标并选择编辑方案。选择运行,然后从信息选项卡中选择发布。
  4. 无需其他设置。
  5. 现在,由于模拟器在x86架构上运行,因此可以为任何模拟器构建框架。
  6. 单击项目浏览器中的“产品”组,然后找到.framework文件。
  7. 右键单击它,然后单击“在Finder中显示”。将其复制并粘贴到任何文件夹中,我个人更喜欢使用“模拟器”这个名称。
  8. 现在,为通用iOS设备构建框架,并按照步骤6到9进行操作。只需将文件夹重命名为“设备”而不是“模拟器”即可。
  9. 复制设备.framework文件并粘贴到任何其他目录中。我更喜欢两者的直接超级目录。因此,目录结构现在变为:
    • 桌面
    • 设备
      • MyFramework.framework
    • 模拟器
      • MyFramework.framework
    • MyFramework.framework现在打开终端,然后将cd转到桌面。现在开始输入以下命令:

lipo-创建'device / MyFramework.framework / MyFramework''模拟器/MyFramework.framework/MyFramework'-输出'MyFramework.framework / MyFramework'

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


我想创建启用了位码的FAT文件。请指导我。
user3898700

2

我只想通过@odm 更新这个好答案。从Xcode 10开始,该CURRENT_ARCH变量不再反映构建体系结构。所以我改为更改脚本来检查平台:

echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
    cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
    cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

我还添加了一行以在复制之前清除目标目录,因为我注意到子目录中的其他文件不会被覆盖。


1

我的答案涵盖以下几点:

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

  • 如何导出“胖”可可触摸框架(适用于模拟器和设备)?

  • 架构x86_64的未定义符号

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

步骤1:首先使用Simulator目标构建框架

步骤2:在模拟器构建过程成功完成之后,现在可以使用设备目标选择或通用iOS设备选择为您的框架构建

步骤3:现在选择您的框架目标,并在“构建阶段”下选择“添加运行脚本”并复制以下脚本代码)

步骤4:现在,最后,再次构建,您的框架已为模拟器和设备兼容性做好了准备。欢呼!!!!

[注意:我们必须在最终步骤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"


该脚本似乎会自称,从而导致无限循环!!运行后必须重新启动我的计算机!不断产生新的xcodebuild流程...并打开新的查找器窗口-会否投票
J.beenie '17

在此SO Q / A中查看@ l0gg3r的答案,以获得类似的脚本,而没有递归问题。
J.beenie'5
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.