XCFramework — 一种Apple二进制格式,将iOS、macOS、tvOS和watchOS的库合并到一个包中。设计用于替代.framework并解决在为不同模拟器和设备架构编译时出现的fat binary问题。根据Apple WWDC 2019的信息,XCFramework已成为支持多平台的SDK交付的强制格式,并完全取代了使用通用二进制文件的过时方法。
要点
XCFramework — Apple在WWDC 2019上引入的二进制库和框架的打包格式。主要目的是创建一个bundle,其中包含库针对所有目标平台和架构的编译版本。
在XCFramework出现之前,开发人员使用.framework配合fat binary,通过lipo工具合并多个架构。这种方法带来了问题:在为模拟器编译项目时,fat binary同时包含模拟器和设备的架构,导致在将构建提交到App Store时出错。开发人员需要编写Run Script阶段来删除不需要的架构。
根据Apple Developer Documentation(2024),XCFramework支持Apple生态系统的所有平台:iOS、iPadOS、macOS、tvOS、watchOS、visionOS和催化剂应用程序。每个平台在包内获得独立的切片,消除了架构冲突并简化了SDK的分发。
XCFramework适用于三种主要场景:向第三方开发人员交付闭源SDK、分发Flutter和React Native的原生模块、以及发布需要预编译的库。该格式对于在Apple生态系统中发布的所有新SDK是强制性的。
当源代码无法公开、库使用专有算法或需要许可证保护时,开发人员会选择XCFramework。与使用源代码的Swift Package Manager不同,XCFramework提供已编译的二进制文件。
Fat binary问题在于通用二进制文件在一个Mach-O文件中包含多个架构。在为模拟器编译应用程序时,Xcode在二进制文件中包含了设备的arm64架构和模拟器的x86_64架构 — App Store只接受设备架构。
传统解决方案包括添加Run Script阶段,调用lipo从最终构建中删除模拟器架构。这种方法很脆弱,在Xcode更新或添加新架构(例如Apple Silicon上模拟器的arm64)时容易出错。
根据Swift.org(2023),Swift Package Manager团队在尝试支持二进制依赖项时最初遇到了这个问题。XCFramework在格式层面上解决了它:每个切片都是一个单独的文件夹,包含描述目标平台和架构的Info.plist。Xcode在编译时自动选择正确的切片,无需后期处理。
XCFramework中的每个切片仅包含一个平台和架构的组合。例如,ios-arm64仅包含iOS设备的二进制文件,而ios-x86_64-simulator仅包含Intel Mac模拟器的二进制文件。Xcode自动选择正确的切片,消除了架构删除脚本的需求,并降低了编译错误的风险。
ios-arm64-x86_64-simulator切片是为了支持Apple Silicon Mac而出现的。以前,模拟器需要arm64(Apple Silicon)和x86_64(Intel)的独立二进制文件。XCFramework允许在模拟器的单个切片内使用fat binary — 这是fat binary唯一合理的例外情况。
XCFramework包是一个扩展名为.xcframework的目录,顶层包含Info.plist和包含二进制切片的文件夹。每个切片包含用于特定平台的.framework或.a库。
MyLibrary.xcframework/
Info.plist
ios-arm64/
MyLibrary.framework/
Info.plist
MyLibrary
ios-x86_64-simulator/
MyLibrary.framework/
Info.plist
MyLibrary
macos-arm64-x86_64/
MyLibrary.framework/
Info.plist
MyLibrary
包的Info.plist包含AvailableLibraries键,列出了每个切片的LibraryIdentifier、LibraryPath和SupportedPlatform标识符。Xcode在将XCFramework添加到项目时读取此文件,并自动配置搜索路径和Embed Frameworks阶段。
每个切片都是一个完整的.framework或静态库,拥有自己的Info.plist。这使得XCFramework可以支持混合类型:某些平台的静态库和其他平台的动态框架,尽管在实践中所有切片更常使用一种类型。
创建XCFramework通过xcodebuild -create-xcframework完成。该命令接受每个平台已编译的.framework或.a库,并将它们合并到一个包中。
该过程包括两个步骤:首先为每个目标平台编译二进制文件,然后打包到XCFramework中。编译使用标准的Xcode destination标志。
# 第1步:为每个平台构建框架
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS Simulator"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=macOS"
# 第2步:创建XCFramework
xcodebuild -create-xcframework -framework ./iOS/MyLibrary.framework -framework ./iOSSim/MyLibrary.framework -framework ./macOS/MyLibrary.framework -output ./MyLibrary.xcframework
-create-xcframework标志出现在Xcode 11中。该命令自动创建正确的目录结构并生成包含所有平台描述的Info.plist。如果其中一个.framework损坏或使用错误的架构编译,xcodebuild会在验证阶段报错。
对于CI/CD,使用shell脚本来自动化所有平台的编译和XCFramework的创建。流行的做法是使用Makefile或Fastlane lane形式的包装器,参数化scheme和output path。
# build_xcframework.sh — 自动化脚本
set -e
SCHEME="MyLibrary"
OUTPUT="./build"
xcodebuild archive -scheme "$SCHEME" -sdk iphonesimulator -archivePath "$OUTPUT/sim.xcarchive"
xcodebuild archive -scheme "$SCHEME" -sdk iphoneos -archivePath "$OUTPUT/dev.xcarchive"
xcodebuild -create-xcframework -framework "$OUTPUT/dev.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -framework "$OUTPUT/sim.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -output "$OUTPUT/MyLibrary.xcframework"
此类脚本在CI流水线(GitHub Actions、Bitrise、Jenkins)中测试运行后执行。生成的XCFramework被归档并作为发布产物上传,或通过依赖管理器(如CocoaPods)使用pod spec发布。
在Xcode项目中集成XCFramework不需要手动配置搜索路径。只需将.xcframework拖入target的General设置中的Frameworks, Libraries, and Embedded Content部分即可。
与.framework不同,XCFramework不需要添加Run Script阶段来删除模拟器架构。Xcode自动确定可用的切片,只包含当前编译方案所需的切片。对于物理设备,使用ios-arm64切片;对于模拟器,使用ios-arm64-x86_64-simulator或ios-x86_64-simulator。
import MyLibrary
func processData() {
// XCFramework在编译时解析正确的切片
let processor = DataProcessor()
let result = processor.analyze(input: "sample")
print(result)
}
对于CocoaPods,集成通过podspec完成,指定vendored_frameworks和支持的平台列表。依赖管理器自动确定项目需要哪些切片。许多商业SDK — Firebase、Adjust、AppsFlyer — 已迁移到XCFramework以简化安装。
Swift Package Manager和XCFramework不是竞争关系,而是互补的。SPM使用源代码,在每次项目编译时编译依赖项。XCFramework提供现成的二进制文件,不需要在消费者端进行编译。
随着Swift Package Manager 5.3的发布,Apple增加了对二进制依赖的支持 — 现在SPM可以将XCFramework作为远程依赖加载。Package.swift指定二进制产物的URL及其校验和以进行验证。
根据Swift Package Manager documentation(2024),二进制依赖推荐用于不公开源代码的SDK或编译时间不成比例地长的库。对于开源项目,通过SPM以源代码形式交付更可取。
| 标准 | XCFramework | Swift Package Manager |
|---|---|---|
| 格式 | 二进制(.xcframework) | 源代码 |
| 代码保护 | 完全 | 无 |
| 编译时间 | 最小(复制) | 取决于代码量 |
| 平台灵活性 | 所有Apple平台 | 取决于Package.swift |
| 集成 | 拖放或SPM | Package.swift |
常见问题解答
.framework — 一种过时的格式,包含带有设备和模拟器架构的fat binary。XCFramework单独存储每个切片,消除了编译时的架构冲突。Apple建议所有新项目和现有迁移使用XCFramework。
CocoaPods从1.9版本开始支持XCFramework。在podspec中只需指定spec.vendored_frameworks和spec.static_framework。管理器会自动解析依赖关系,考虑项目平台可用的切片。
Apple不会删除对.framework的支持,但对于新SDK,建议仅使用XCFramework。使用旧格式的fat binary向App Store提交应用程序时,由于模拟器架构可能会出现Invalid Bundle错误,这使得XCFramework成为实际必要。
从Swift 5.3开始,SPM中的二进制依赖使用XCFramework。Package.swift指定二进制包的url和checksum。SPM下载、验证完整性,并将XCFramework作为系统依赖连接,无需编译源代码。
visionOS从Xcode 15开始在XCFramework中得到支持。在WWDC 2023上,Apple确认该格式已扩展支持Apple Vision Pro。visionOS切片的SupportedPlatform = xros,包含arm64架构。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。