闭源二进制动态框架依赖开源框架,运行时库加载失败如何解决?
Swift Package 动态二进制框架依赖运行时加载问题
我在为依赖多个非二进制开源动态框架的闭源二进制动态框架编写Package.swift文件时遇到了问题。
当前的Package.swift内容如下:
// swift-tools-version: 5.8 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription import Foundation let package = Package( name: "MyLibrary", platforms: [ .iOS(.v12) ], products: [ .library( name: "MyLibrary", targets: ["MyLibraryWrapper"] ), ], dependencies: [ .package(url: "<dependency-url>", branch: "master"), ], targets: [ .target( name: "MyLibraryWrapper", dependencies: [ .target(name: "MyLibrary"), .product(name: "<dependency-product-name>", package: "<dependency-package-name>") ], path: "MyLibraryWrapper" ), .binaryTarget( name: "MyLibrary", url: "<url-to-xcframework-zip>", checksum: "<checksum>" ) ] )
这个包能编译成功,但添加到任意应用后会出现以下运行时错误:
Library not loaded: @rpath/<dependency-product-name>.framework
我目前知道的解决方法是fork每个依赖的源码项目,然后把每个库的library类型声明为.dynamic,但这样需要维护每个依赖的fork,我不想这么做。有没有更优、更简洁的解决方案?
补充说明
- 必须声明
MyLibraryWrappertarget,因为binaryTarget没有提供dependencies参数,无法直接为二进制框架添加依赖。 MyLibraryWrapper对应的目录里只有一个空源码文件,没有其他内容。- 我试过把
MyLibrary的产品类型声明为.dynamic,希望SPM能自动动态链接MyLibrary及其依赖,但会触发"Multiple commands produce MyLibrary.framework"编译错误。 MyLibrary所依赖的非二进制动态框架在它们的Package.swift里没有指定明确的type,这符合Apple的建议:建议不要显式声明库类型,让Swift Package Manager根据使用者的偏好选择静态或动态链接。
解决方案
方法1:强制依赖动态链接(适配性稍弱)
在MyLibraryWrapper的target配置中添加编译标记,强制SPM将依赖库以动态方式链接:
.target( name: "MyLibraryWrapper", dependencies: [ .target(name: "MyLibrary"), .product(name: "<dependency-product-name>", package: "<dependency-package-name>") ], path: "MyLibraryWrapper", swiftSettings: [ .unsafeFlags(["-Xlinker", "-add_ast_path", "$(TARGET_BUILD_DIR)/<dependency-product-name>.framework/Modules/<dependency-product-name>.swiftmodule/x86_64-apple-ios-simulator.swiftmodule"]) ] )
注意:这种方式需要针对不同CPU架构做适配,通用性有限。
方法2:用Package.resolved锁定依赖动态特性(推荐)
- 本地创建临时项目,引入你的
MyLibrary包和所有依赖,在Xcode中将项目的Build Settings→MACH_O_TYPE设为dynamiclib,强制以动态方式编译所有依赖。 - 编译成功后,将临时项目根目录下的
Package.resolved文件复制到你的MyLibrary包根目录中。 - 其他项目引入
MyLibrary时,SPM会遵循Package.resolved的配置,自动以动态方式链接依赖库,避免运行时找不到框架的问题。
方法3:调整产品类型并规避编译冲突
修改products中MyLibrary的类型为.dynamic,同时调整target结构避免重复生成框架:
products: [ .library( name: "MyLibrary", type: .dynamic, targets: ["MyLibraryWrapper"] ), ],
同时在MyLibraryWrapper的编译设置中,将FRAMEWORK_SEARCH_PATHS指向二进制框架的路径,确保编译时不会出现冲突。此方法需保证二进制框架本身的依赖逻辑正确。
内容的提问来源于stack exchange,提问作者ale-gen
相关产品推荐
相关产品推荐

