運維 / CI·CD 2026年5月20日

2026-05-20 Xcode 16 描述檔路徑多車道併發 Archive:在無頭租用的 Apple Silicon 雲端 Mac 上落地(香港 / 東京 / 首爾 / 新加坡 / 美國

MacXCode 技術團隊 2026年5月20日 约 18 分钟阅读

香港、東京、首爾、新加坡、美國租用Mac mini M4并以無頭 SSH运行 Xcode 16 的团队,会碰到一个并不张扬的破坏性变更:描述檔(Provisioning Profile)不再只住在传统的 MobileDevice 目录里。Xcode 16UserData 为权威读写位置,而 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
数值护栏:轮换发行描述檔时保留 7–14 天 有效期重叠;进行中的 Archive 结束前不要删除旧 UUID。每次 Archive 前记录最新三个描述檔的 mtime,并與 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-keychainssecurity find-identity -v -p codesigning,以及对两个描述檔目录按 mtime 列出的最新三个 UUID。

codesignerrSecInternalComponent,在 archive 前非交互解锁 CI 鑰匙串、配置 codesign 分区列表,并核对描述檔 entitlement 與目标能力是否一致(推送、App Group、Associated Domains 在门户修改后尤需复查)。自动簽名 + ASC API 可能把路徑问题推迟到导出阶段才暴露;手动車道会立刻显现。混用車道前请先读《自动與手动簽名》。

切勿在共享租机上让两条車道共用同一登录鑰匙串。在 /var/ci 下创建 ci-lane-a.keychain-dbci-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

  1. xcode-select 固定到目标 Xcode 16.app,并把 xcodebuild -version 写入黄金鏡像清单。
  2. 审计所有复制 .mobileprovision 的脚本,改为以 UUID 文件名双写 UserData 與 MobileDevice。
  3. 为每条車道创建 CI 鑰匙串并导入发行证书,禁止互访对方鑰匙串文件。
  4. 在 CI 环境块导出 KEYCHAIN_PATHPROVISIONING_PROFILE_SPECIFIER 與車道级 DERIVED_DATA_ROOT
  5. 每条車道干跑 xcodebuild -showBuildSettings,确认 CODE_SIGN_STYLE 與簽名策略一致。
  6. 仅在 ASC API 凭证已密封监控时启用 -allowProvisioningUpdates
  7. 先稳定单車道 Archive,再开第二条車道并分离 NVMe 根與日志。
  8. 按周执行磁碟清理;轮换描述檔保留重叠,并在車道暂存目录保留热切换副本。

非交互安装描述檔(将 $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》一并阅读。

租用 Apple Silicon,让 Xcode 16 簽名可预测

HK / JP / KR / SG / US · 無頭 SSH · 多車道 Archive 就绪