DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

真机能编译,iOS 模拟器却提示链接了 iOS 库:检查 XCFramework 的平台切片

真机构建成功、模拟器报平台不匹配或缺库时,核对 XCFramework 的平台与架构切片,分别归档并统一打包,明确旧库临时排除 arm64 的限制。

同一个工程在 iPhone 上构建成功,换成模拟器后却报 building for iOS Simulator, but linking in object file built for iOS,或 While building for iOS Simulator, no library was found。先找到错误里点名的二进制依赖:它可能只有真机版本,也可能把真机与模拟器的二进制错误地合在了一起。

这类问题常见于 Xcode 12 以后接入旧的预编译库,尤其是从 Intel Mac 迁到 Apple silicon 后。本文处理 .framework、静态库与 .xcframework 的平台兼容问题;如果错误是找不到 Swift 模块、签名失败或最低系统版本不符,需要按对应诊断另查。

arm64 相同,不代表平台相同

Apple silicon 上的 iOS 模拟器和 iPhone 都可能使用 arm64,但编译目标分别是 iOS Simulator 和 iOS。CPU 架构匹配只是链接条件之一,平台也必须匹配。

因此,下面的只读命令只能确认二进制包含哪些 CPU 架构,不能证明它支持模拟器。把示例路径替换为错误中实际出现的文件:

file Vendor.framework/Vendor
lipo -info Vendor.framework/Vendor

如果依赖是 XCFramework,再检查它的清单:

plutil -p Vendor.xcframework/Info.plist

在 AvailableLibraries 中,分别寻找 iOS 真机项和模拟器项。模拟器项的 SupportedPlatform 为 ios,SupportedPlatformVariant 为 simulator;其 SupportedArchitectures 还须覆盖当前模拟器需要的架构。目录名可以帮助定位,但应以清单和实际二进制为准。只有 ios 真机项的 XCFramework 仍然不能用于模拟器。

还要展开失败的链接命令,核对被选中的依赖路径。项目里放着新版 XCFramework,并不代表构建系统没有继续引用旧 .framework;Framework Search Paths、Link Binary With Libraries 和依赖管理工具生成的配置都可能保留旧路径。

有源码:分别归档,再打成一个 XCFramework

准备一个只构建库本身及其依赖的共享 scheme。以下示例假设工程和 scheme 都叫 ExampleKit,应替换为自己的名称;输出目录应是新的专用目录,已有同名归档或发布产物先另存。

xcodebuild archive \
  -project ExampleKit.xcodeproj \
  -scheme ExampleKit \
  -destination 'generic/platform=iOS' \
  -archivePath './xcframework-output/ExampleKit-iOS.xcarchive' \
  SKIP_INSTALL=NO \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

xcodebuild archive \
  -project ExampleKit.xcodeproj \
  -scheme ExampleKit \
  -destination 'generic/platform=iOS Simulator' \
  -archivePath './xcframework-output/ExampleKit-Simulator.xcarchive' \
  SKIP_INSTALL=NO \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

xcodebuild -create-xcframework \
  -framework './xcframework-output/ExampleKit-iOS.xcarchive/Products/Library/Frameworks/ExampleKit.framework' \
  -framework './xcframework-output/ExampleKit-Simulator.xcarchive/Products/Library/Frameworks/ExampleKit.framework' \
  -output './xcframework-output/ExampleKit.xcframework'

SKIP_INSTALL=NO 让库产物进入归档;BUILD_LIBRARY_FOR_DISTRIBUTION=YES 对 Swift 库启用库演进和模块接口生成。架构设置通常保留 Xcode 默认值,让每个平台构建所需架构。若使用 workspace,把 -project 换成实际的 -workspace 参数。

关键是最后一次调用同时传入两个平台的 framework。分别生成一个真机 XCFramework 和一个模拟器 XCFramework,不会自动得到包含两者的发行包。-create-xcframework 负责打包已有产物,不会给真机库补编译出模拟器支持。

如果输出是 .a 静态库,使用 -library 并按需提供 -headers,同样为两个平台分别编译。不要用 lipo 把 iOS 与 iOS Simulator 合成一个二进制。模拟器自身不同 CPU 架构的组合,与跨平台合并是两回事。

没有源码:换兼容发行包,临时绕过要有边界

第三方闭源库应升级到包含所需模拟器切片的 XCFramework。更新后让依赖管理工具重新解析,再确认链接命令确实指向新版产物;不要直接修改 Pods 里的二进制来代替版本更新。

供应方暂时没有更新时,只有当前 Xcode、已安装的模拟器运行时和依赖都支持相应 Rosetta 目的地,才考虑临时排除模拟器的 arm64。设置必须限定为 Any iOS Simulator SDK,不能作用于真机 SDK。Xcode 14.3 起可在 Product > Destination > Destination Architectures 中选择 Rosetta 目的地;实际是否有可用目的地,以当前工具链为准。

不要把“排除 arm64”写成整个项目的永久修复,也不要让 Xcode 本身通过 Rosetta 启动来处理这个错误。拿到兼容库后撤销临时排除,恢复 Apple silicon 模拟器构建。

修好后分别验证两个目标

先检查新包清单包含真机与模拟器项,再分别选择实际 iPhone 和当前 Mac 可运行的模拟器构建。成功标准是两边都链接到预期版本,不再出现平台不匹配或缺库错误,并能启动到使用该依赖的功能。

只在真机上成功,不能证明模拟器切片完整;只改设置消掉一条错误,也不能证明库里的功能已可用。若仍失败,保留最新完整链接诊断,继续追踪它点名的下一个依赖,而不是反复清缓存。