将 XCFrameworks 集成到开发和发布工作流中
Integrating XCFrameworks into the development and release workflows
我有一个 Xcode 工作区,其中有一个 iOS 框架目标和一个 iOS SampleApp 目标,它依赖于并嵌入框架。该框架是封闭源代码的,因此以二进制形式交付给客户,在一个发布包中连同整个 SampleApp 项目的源代码副本,以便他们可以使用我们的应用程序对其进行测试并查看集成是如何完成的。
使用此设置,在开发阶段,我可以在 Xcode 中打开工作区并构建 SampleApp 目标,因为它对框架有明确的依赖性,Xcode 立即触发首先构建框架,然后构建应用程序并正确 linked。
现在我想利用新的 XCFramework 格式 将此框架分发给客户,而不是使用 lipo'ed fat 框架。我更新了生成发布包的 shell 脚本,以在支持所有各种平台的最后创建一个 xcframework 包,并且还更新了 SampleApp 项目以依赖于此 xcframework 而不是像以前那样依赖于各个框架.
但是更新后的 SampleApp 的问题来了:移除对框架的依赖后,上面描述的工作区设置不再起作用,即 Xcode 将不再自动构建框架目标。 SampleApp 目标已构建,因为两者之间的显式依赖关系 link 现在已被打破。
我解决这个问题的第一次尝试涉及将 xcframework 也纳入我的常规开发工作流程。为此,我向框架构建目标添加了一个 运行-script 阶段,该阶段生成一个当前平台专用的 xcframework 包并将其复制到 SampleApp 希望找到它的地方,然后将框架目标添加到SampleApp 构建方案的目标,以便在构建 SampleApp 时构建框架。不幸的是,这种方法不起作用,因为 Xcode 12 似乎总是并行构建两个目标,无论 'Parallelize Build' 设置如何,并且由于 xcframework 的原因,应用程序将无法构建当它被构建系统处理时还没有准备好,这是在 SampleApp 的构建阶段的早期。因此,除非有办法强制 Xcode 遵守方案中定义构建目标的顺序,否则这种方法是行不通的。
如果这种方法行不通,那么我将不得不交付带有未修改的 SampleApp 的 xcframework,并指示想要 运行 应用程序的客户手动删除对通用框架的引用,然后 add/drag xcframework 到它。这可行,但它很丑陋,而且对我来说似乎不够友好。
我也在考虑一种不同的方法,即发布脚本以编程方式修改 SampleApp.xcodeproj 以依赖于 xcframework 而不是通用框架,但这似乎是一件非常脆弱的事情,所以如果有更好的方法,宁愿避免它。
这种情况对我来说似乎并不独特,所以我猜其他人一定也遇到过这个问题。如果有,你是怎么解决的?
所以我最终通过在发布时以编程方式将 SampleApp 的项目文件修改为 link 并嵌入 xcframework 包而不是通用框架来解决这个问题。
最初尝试使用该工具 pbxproj 但效果不佳,最初的 fat 框架删除阶段没有成功。
然后我想我可以在用 xcframework 手动替换框架后尝试比较 project.pbxproj
文件,事实证明只需要一些小的编辑就可以到达那里,所以它们可以通过编程方式完成使用如下简单的 shell 脚本:
#!/bin/bash
PROJECT_FILE=SampleApp/SampleApp.xcodeproj/project.pbxproj
FRAMEWORK_NAME=MyFramework.framework
XCFRAMEWORK_NAME=MyFramework.xcframework
sed -i '' "s|FileType = wrapper.framework; path = ${FRAMEWORK_NAME}; sourceTree = BUILT_PRODUCTS_DIR;|FileType = wrapper.xcframework; path = ${XCFRAMEWORK_NAME}; sourceTree = \"<group>\";|" ${PROJECT_FILE}
sed -i '' "s|${FRAMEWORK_NAME}|${XCFRAMEWORK_NAME}|g" ${PROJECT_FILE}
其他项目设置可能存在细微差异,但主要归结为这一点。请注意,如果要将 xcframework 放置在项目根目录以外的其他位置,那么您需要在第一个 sed
命令中同时使用 name
和 path
属性,例如:
name = "MyFramework.xcframework"; path = "relative/path/to/MyFramework.xcframework"
我有一个 Xcode 工作区,其中有一个 iOS 框架目标和一个 iOS SampleApp 目标,它依赖于并嵌入框架。该框架是封闭源代码的,因此以二进制形式交付给客户,在一个发布包中连同整个 SampleApp 项目的源代码副本,以便他们可以使用我们的应用程序对其进行测试并查看集成是如何完成的。
使用此设置,在开发阶段,我可以在 Xcode 中打开工作区并构建 SampleApp 目标,因为它对框架有明确的依赖性,Xcode 立即触发首先构建框架,然后构建应用程序并正确 linked。
现在我想利用新的 XCFramework 格式 将此框架分发给客户,而不是使用 lipo'ed fat 框架。我更新了生成发布包的 shell 脚本,以在支持所有各种平台的最后创建一个 xcframework 包,并且还更新了 SampleApp 项目以依赖于此 xcframework 而不是像以前那样依赖于各个框架.
但是更新后的 SampleApp 的问题来了:移除对框架的依赖后,上面描述的工作区设置不再起作用,即 Xcode 将不再自动构建框架目标。 SampleApp 目标已构建,因为两者之间的显式依赖关系 link 现在已被打破。
我解决这个问题的第一次尝试涉及将 xcframework 也纳入我的常规开发工作流程。为此,我向框架构建目标添加了一个 运行-script 阶段,该阶段生成一个当前平台专用的 xcframework 包并将其复制到 SampleApp 希望找到它的地方,然后将框架目标添加到SampleApp 构建方案的目标,以便在构建 SampleApp 时构建框架。不幸的是,这种方法不起作用,因为 Xcode 12 似乎总是并行构建两个目标,无论 'Parallelize Build' 设置如何,并且由于 xcframework 的原因,应用程序将无法构建当它被构建系统处理时还没有准备好,这是在 SampleApp 的构建阶段的早期。因此,除非有办法强制 Xcode 遵守方案中定义构建目标的顺序,否则这种方法是行不通的。
如果这种方法行不通,那么我将不得不交付带有未修改的 SampleApp 的 xcframework,并指示想要 运行 应用程序的客户手动删除对通用框架的引用,然后 add/drag xcframework 到它。这可行,但它很丑陋,而且对我来说似乎不够友好。
我也在考虑一种不同的方法,即发布脚本以编程方式修改 SampleApp.xcodeproj 以依赖于 xcframework 而不是通用框架,但这似乎是一件非常脆弱的事情,所以如果有更好的方法,宁愿避免它。
这种情况对我来说似乎并不独特,所以我猜其他人一定也遇到过这个问题。如果有,你是怎么解决的?
所以我最终通过在发布时以编程方式将 SampleApp 的项目文件修改为 link 并嵌入 xcframework 包而不是通用框架来解决这个问题。
最初尝试使用该工具 pbxproj 但效果不佳,最初的 fat 框架删除阶段没有成功。
然后我想我可以在用 xcframework 手动替换框架后尝试比较 project.pbxproj
文件,事实证明只需要一些小的编辑就可以到达那里,所以它们可以通过编程方式完成使用如下简单的 shell 脚本:
#!/bin/bash
PROJECT_FILE=SampleApp/SampleApp.xcodeproj/project.pbxproj
FRAMEWORK_NAME=MyFramework.framework
XCFRAMEWORK_NAME=MyFramework.xcframework
sed -i '' "s|FileType = wrapper.framework; path = ${FRAMEWORK_NAME}; sourceTree = BUILT_PRODUCTS_DIR;|FileType = wrapper.xcframework; path = ${XCFRAMEWORK_NAME}; sourceTree = \"<group>\";|" ${PROJECT_FILE}
sed -i '' "s|${FRAMEWORK_NAME}|${XCFRAMEWORK_NAME}|g" ${PROJECT_FILE}
其他项目设置可能存在细微差异,但主要归结为这一点。请注意,如果要将 xcframework 放置在项目根目录以外的其他位置,那么您需要在第一个 sed
命令中同时使用 name
和 path
属性,例如:
name = "MyFramework.xcframework"; path = "relative/path/to/MyFramework.xcframework"