You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:03:15