Swift动态框架打包XCFramework嵌入App报unable to find bundle错误
核心原因
崩溃本质是资源路径匹配缺失:当依赖Swift Package的动态框架被打包为XCFramework时,SPM自动生成的资源bundle不会被放到你当前Bundle.myModule覆盖的常规路径下——它既不在App主Bundle目录,也不在框架的Resources根目录,而是会被Xcode默认嵌入到XCFramework架构切片内部的Frameworks子目录,原有遍历逻辑完全没覆盖这个路径,自然触发找不到资源的崩溃。
排查方向
- 先确认资源实际存放位置:解压生成的XCFramework,进入对应架构切片目录(比如
ios-arm64/myFramework.framework),逐层查找名为xxxx.bundle的文件,记录它的相对路径,常见存放位置包括切片下的Frameworks/目录、Resources/目录、框架二进制同层级目录三类。 - 检查打包配置:确认打包XCFramework时对应Target的
SKIP_INSTALL配置为NO,同时检查Build Phases中没有配置过滤.bundle文件的自定义脚本,避免资源在构建阶段被误删。 - 检查类访问权限:确认SPM内定义的
CurrentBundleFinder类访问权限为public/open,如果是internal/private,Bundle(for:)拿到的会是错误的bundle对象,直接导致后续路径计算全错。 - 检查宿主嵌入逻辑:确认宿主项目嵌入XCFramework时没有勾选
Copy only when installing,同时Embed Frameworks阶段没有配置剥离内部资源的规则。
可行解决方法
方案1:补全Bundle查找路径(侵入性最低,优先选择)
在现有myModule闭包的候选路径数组中,补充XCFramework场景下的路径,同时增加一级子目录遍历逻辑,覆盖路径层级偏差的情况。
首先在candidates数组中新增以下路径:
// XCFramework内嵌SPM资源的默认路径 Bundle(for: CurrentBundleFinder.self).resourceURL?.appendingPathComponent("Frameworks"), // 开启BUILD_LIBRARY_FOR_DISTRIBUTION时的资源相对路径 Bundle(for: CurrentBundleFinder.self).resourceURL?.appendingPathComponent("../../Frameworks"), // 静态合并场景下框架根目录路径 Bundle(for: CurrentBundleFinder.self).bundleURL
然后修改遍历逻辑,增加子目录匹配:
for candidate in candidates { // 原有直接匹配bundle的逻辑保留 let bundlePathiOS = candidate?.appendingPathComponent(bundleNameIOS + ".bundle") if let bundle = bundlePathiOS.flatMap(Bundle.init(url:)) { return bundle } // 新增:遍历候选路径下一级子目录匹配bundle if let candidateURL = candidate, let dirContents = try? FileManager.default.contentsOfDirectory(at: candidateURL, includingPropertiesForKeys: nil) { for fileURL in dirContents where fileURL.lastPathComponent == "\(bundleNameIOS).bundle" { if let targetBundle = Bundle(url: fileURL) { return targetBundle } } } // 原有主Bundle路径匹配逻辑保留 if let bundle = Bundle(path: "\(Bundle.main.bundlePath)/\(bundleNameIOS).bundle") { return bundle } }
方案2:打包阶段手动拷贝资源到可识别路径
如果无法修改对应SPM的源码(比如依赖是远端公开库),可以在框架Target的Build Phases中新增Run Script阶段,放在Embed Frameworks阶段之后执行,构建时自动把SPM生成的资源bundle拷贝到框架根目录:
# 替换为你实际的bundle名和框架名 TARGET_BUNDLE="xxxx.bundle" TARGET_FRAMEWORK="myFramework" # 从构建临时目录查找SPM生成的资源bundle find "$BUILT_PRODUCTS_DIR" -name "$TARGET_BUNDLE" -type d | while read -r BUNDLE_PATH do cp -R "$BUNDLE_PATH" "$BUILT_PRODUCTS_DIR/$TARGET_FRAMEWORK.framework/" done
方案3:调整SPM依赖的链接方式
如果以上两个方案都不生效,可以把带资源的SPM依赖从动态库改为静态库:在Xcode的Target配置中找到对应SPM依赖项,将Mach-O Type修改为Static Library。此时SPM的资源会在编译阶段被直接合并到主框架的资源目录,不会生成嵌套的独立bundle,原有查找逻辑不需要修改即可正常工作。
注意:该方案仅适用于没有其他动态框架同时依赖这个SPM的场景,否则会出现符号重复冲突的问题。
内容的提问来源于stack exchange,提问作者Malcolmn Roberts
相关产品推荐
相关产品推荐

