2026-05-20 Xcode 16 描述文件路径与多车道并发 Archive:在无头租用的 Apple Silicon 云 Mac 上落地(香港 / 东京 / 首尔 / 新加坡 / 美国)
在香港、东京、首尔、新加坡、美国租用Mac mini M4并以无头 SSH运行 Xcode 16 的团队,会碰到一个并不张扬的破坏性变更:描述文件(Provisioning Profile)不再只住在传统的 MobileDevice 目录里。Xcode 16 以 UserData 为权威读写位置,而 2024 年以前的脚本、部分 Fastlane 动作与内部安装器仍只往旧路径复制 .mobileprovision。当你在单台租机上叠加多车道并发 xcodebuild archive 时,路径漂移会演变成签名竞态、虚假的「找不到描述文件」以及仅在 CI 上复现的 errSecInternalComponent。本文在开头给出策略:在主机上所有工具都确认兼容 Xcode 16 之前,双写镜像 UserData 与旧版路径;为每条车道配置独立 CI 钥匙串与DerivedData 根目录;在标配 Mac mini M4 上把并发 Archive 车道默认限制为两条。正文提供路径对照表、多车道矩阵、无头签名排障、八步上线清单与 FAQ,并与《钥匙串与描述文件 CI 基线》《自动与手动签名》《并发 xcodebuild 纪律》互相衔接。
谁会遇到描述文件路径漂移
失败信息很少直接写「目录错了」。更常见的是:车道 B 的 Archive 成功,车道 A 却报 No profile for team 'XXXXXXXXXX' matching,而两边明明导入同一 UUID。租机上问题会被放大:黄金镜像里残留 2024 年的安装脚本、插件仍只刷新 ~/Library/MobileDevice/Provisioning Profiles,新人本地的 Fastlane 却把文件下载进 UserData,夜间 cron 却只同步旧目录。多分支 CI 若共用同一 macOS 用户且未刻意分区,home 目录下的隐式全局状态会把「独立任务」绑在一起。
- 发布工程师需要在单台 Mac mini M4 上为不同 Bundle ID 并发 Archive,并要求每条车道可预测地解析描述文件。
- 平台组维护黄金镜像时必须写清:Xcode 16、
xcodebuild与辅助工具在archive/exportArchive时读哪条路径。 - 安全评审要求证明车道 A 无法读取车道 B 的发行证书——热切换描述文件时,按车道隔离钥匙串 不可省略。
设计评审可从 MacXCode 首页 出发:Apple Silicon 贴近 Apple API,再判断哪些签名物料必须与租机检出同驻。若仍只复制到 MobileDevice,应视为阻碍多车道吞吐的技术债——请与《远程 Archive 指南》对照阅读(该文早于 UserData 变更)。
旧版 MobileDevice 与 Xcode 16 UserData 路径
Xcode 16 在通过 Xcode「账户」下载描述文件,或使用 xcodebuild -allowProvisioningUpdates 刷新 entitlement 时,会把磁盘上的权威位置视为 ~/Library/Developer/Xcode/UserData/Provisioning Profiles。旧路径 ~/Library/MobileDevice/Provisioning Profiles 仍被大量 CI 配方与脚本使用。在审计完所有入口之前,运维上的安全缺省是:每次轮换后把同一份 .mobileprovision 以 plist 内嵌的 UUID 为文件名,字节级一致地复制到两处(可用 security cms -D -i 读取 UUID)。
| 路径 | 典型消费者 | Xcode 16 行为 | 租用机 CI 提示 |
|---|---|---|---|
~/Library/Developer/Xcode/UserData/Provisioning Profiles |
Xcode IDE、新版 xcodebuild |
GUI 下载的权威读写位置 | 复制前先 xcode-select 固定版本 |
~/Library/MobileDevice/Provisioning Profiles |
旧脚本、部分 Fastlane | 许多 CLI 流程仍会读取 | 脚本退役前继续镜像 |
车道暂存(如 /var/ci/lane-a/profiles) |
自定义安装器 | 不被直接读取,降低 home 竞态 | 每 job 再复制到两条 canonical 路径 |
ASC API + -allowProvisioningUpdates |
自动签名流水线 | 可能只写入 UserData | 见《Fastlane 与原生 ASC》 |
security find-identity -v -p codesigning 一并写入日志,做法见《钥匙串基线》。
单台 Mac mini M4 上的多车道并发 Archive 矩阵
并发 Archive 不是「免费并行」:统一内存、NVMe 队列深度与签名会话状态在负载下仍会相互牵制。下表假设每条车道有独立 -derivedDataPath、独立 CI 钥匙串与双路径镜像的描述文件——细节见《并发 xcodebuild》与《Scheme + xcconfig 多分支》。
| 车道数 | 典型 NVMe 余量 | 统一内存 | 运维结论 |
|---|---|---|---|
| 1 条串行 Archive | 系统卷至少 120GB 可用 | 16GB 起步,24GB 更舒适 | 共享 Release 列车默认方案 |
| 2 条并发 Archive | 每车道在 /var/ci 预留 120–180GB |
建议 24GB+ | 标配 M4 的务实上限 |
| 3 条及以上 | 2TB 级 NVMe + 积极清理 | 32GB+,否则易压缩抖动 | 需有指标支撑;配合《磁盘清理》 |
| Archive + 重测试分片 | 根目录分离,勿共享 ModuleCache | 为 XCTest 留 4GB 余量 | 优先串行 Archive 或分机 |
手动签名、显式描述文件说明符的车道级 archive 示例:
KEYCHAIN_PATH=/var/ci/lane-a/ci.keychain-db DERIVED=/var/ci/lane-a/dd xcodebuild -workspace App.xcworkspace -scheme Release -configuration Release -archivePath /var/ci/lane-a/out/App.xcarchive -derivedDataPath "$DERIVED" CODE_SIGN_STYLE=Manual PROVISIONING_PROFILE_SPECIFIER='MyApp AppStore' archive
无头签名排障:描述文件「已安装」仍失败
SSH 像交互式会话;launchd 与 CI runner 不是。升级到 Xcode 16 后最常见三类问题:只复制到 MobileDevice;证书进了登录钥匙串但 xcodebuild 指向空的 CI 钥匙串;车道 B 解锁了车道 A 仍占用的钥匙串。请把每次 Archive 的三段指纹当作例行输出:security list-keychains、security find-identity -v -p codesigning,以及对两个描述文件目录按 mtime 列出的最新三个 UUID。
若 codesign 报 errSecInternalComponent,在 archive 前非交互解锁 CI 钥匙串、配置 codesign 分区列表,并核对描述文件 entitlement 与目标能力是否一致(推送、App Group、Associated Domains 在门户修改后尤需复查)。自动签名 + ASC API 可能把路径问题推迟到导出阶段才暴露;手动车道会立刻显现。混用车道前请先读《自动与手动签名》。
/var/ci 下创建 ci-lane-a.keychain-db 与 ci-lane-b.keychain-db,用 security import -k "$KEYCHAIN_PATH" -P "$P12_PASS" -T /usr/bin/codesign 导入发行 .p12,并在每个 job 生命周期内用 security list-keychains -s 限定搜索列表。
| 现象 | 高概率原因 | 下一步 |
|---|---|---|
| Xcode 报告缺少描述文件 | UserData 为空,仅写了旧路径 | 镜像 UUID 到 UserData 后重跑 |
errSecInternalComponent |
钥匙串未解锁或分区列表错误 | security unlock-keychain + set-key-partition-list |
| 同提交车道 A 过、B 败 | 共享 DerivedData 或复制竞态 | 分离 -derivedDataPath,串行化复制 |
| 导出成功、上传被拒 | 描述文件类型或 entitlement 过期 | 对照《导出与 ASC 上传》清单 |
Archive 完成后请先上传 dSYM 再清理车道目录——《dSYM 符号化》假设 /var/ci/…/out 下归档仍可寻址。
八步上线:Xcode 16 路径 + 多车道 Archive
- 用
xcode-select固定到目标 Xcode 16.app,并把xcodebuild -version写入黄金镜像清单。 - 审计所有复制
.mobileprovision的脚本,改为以 UUID 文件名双写 UserData 与 MobileDevice。 - 为每条车道创建 CI 钥匙串并导入发行证书,禁止互访对方钥匙串文件。
- 在 CI 环境块导出
KEYCHAIN_PATH、PROVISIONING_PROFILE_SPECIFIER与车道级DERIVED_DATA_ROOT。 - 每条车道干跑
xcodebuild -showBuildSettings,确认CODE_SIGN_STYLE与签名策略一致。 - 仅在 ASC API 凭证已密封监控时启用
-allowProvisioningUpdates。 - 先稳定单车道 Archive,再开第二条车道并分离 NVMe 根与日志。
- 按周执行磁盘清理;轮换描述文件保留重叠,并在车道暂存目录保留热切换副本。
非交互安装描述文件(将 $PROFILE 换为车道暂存路径):
UUID=$(security cms -D -i "$PROFILE" | plutil -extract UUID raw -) && cp "$PROFILE" "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/$UUID.mobileprovision" && cp "$PROFILE" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision"
常见问题
Xcode 16 把描述文件存在哪里? 主路径为 ~/Library/Developer/Xcode/UserData/Provisioning Profiles。旧工具可能仍读 ~/Library/MobileDevice/Provisioning Profiles——在 CI 主机上应双写镜像直至全部安装器升级。
一台 Mac mini M4 能跑几条并发 Archive? 默认建议两条车道,各预留 120–180GB NVMe;第三条需 2TB 存储、积极清理与审慎内存规划。
SSH 上 codesign 报 errSecInternalComponent 常见原因? 多为钥匙串未解锁、CI 钥匙串分区列表错误或仅写入旧版路径而 Xcode 16 优先解析 UserData。
车道能否共享 DerivedData 提速? Release Archive 不建议——并行时 ModuleCache 与索引存储会竞态。请使用 per-lane -derivedDataPath;依赖缓存仅在单一写入者解析包后再以只读方式共享。
请把 博客列表 与 帮助中心 加入值班书签,避免在聊天窗口里翻找这篇运维手册。
为何 Mac mini M4 租用适合多车道 Xcode 16 Archive
Apple Silicon M4 在诚实隔离 DerivedData、控制车道数量时,足以并行编译两个中等规模的 iOS 工程图。原生 macOS 代码签名可避免模拟 Mac 环境的钥匙串怪异问题——当三条夜间分支都要刷新发行描述文件时尤为关键。租用把 CapEx 变成可按发布周启停的费用:贴近 App Store Connect 可选东京,服务东盟流量可选新加坡,需要美西 API 端点则选美国节点。请在 定价页 对比区域,在 帮助中心 预演 SSH;新仓库接入无头租机时请与《远程 Archive》一并阅读。