2026-04-30 iOS CI 遷移:從 Intel x86_64 到 Apple Silicon ARM64,在租賃雲 Mac 上使用 xcodebuild(香港 / 日本 / 韓國 / 新加坡 / 美國)
Apple 仍交付面向 Intel 的 Xcode,但 2026 年多數移動團隊不再願意為早已不隨包分發的 x86_64 切片支付雲稅。若隊列仍指向老舊 Intel Mac mini,而產物已是 arm64 唯一,你就在資助重複依賴圖與比競爭對手更慢的 xcodebuild test 冷啟動——對手早已把默認構建遷到租在香港、東京、首爾、新加坡、美國的 Mac mini M4。本 2026-04-30 文章是寫給發佈工程的遷移簡報:清點胖二進制、規範 ARCHS、拆掉從不提供 Apple Silicon 切片的 CocoaPods 供應商、用雙隊列矩陣觀察足夠長時間再切默認路由,同時保留斷路 Intel 路徑給偶發舊 CLI。它與 遠程 Archive 與導出、並行 xcodebuild 規劃、多版本 Xcode 與 xcode-select 矩陣 以及 Swift 6 嚴格併發 門禁互補;磁盤與緩存隔離見 DerivedData 與 xcresult 隔離。簽名自動化請繼續用 鑰匙串與描述文件 CI;架構切換常暴露潛伏的配置文件錯配。自託管方面可參考 GitHub Actions 自託管 Runner 清單,把標籤與隊列命名和真實架構對齊,避免“標籤寫 Intel 實際 arm64”的漂移。遷移週期間把 DEVELOPER_DIR 固定寫進作業環境,和共享緩存策略一起評審,否則東京綠、弗吉尼亞紅這類工單會爆炸式增長。對財務團隊,用同一提交在雙隊列上的耗時直方圖說話,比口號“ARM 更快”更有說服力。最後,把 Rosetta 使用限制寫進策略:只有無 arm64 構建的輔助工具才允許翻譯執行,主 iOS 目標禁止依賴 Rosetta 靜默運行。
現狀:筆記本能編不代表 CI 過關
筆記本掩蓋問題:暖模塊緩存、對 Rosetta 透明的工具鏈以及人類耐心。CI 應在數分鐘內暴露。若你處於遷移中段而非完成態,常見信號有三類:鏈接器報 undefined symbols for architecture arm64 同時 lipo -archs 仍列出 vendored 框架上的 x86_64;模擬器 destination 仍寫死在舊 YAML 而新版 Xcode 已移除鏡像;Runner 標籤仍寫 macos-intel 但 shell 實際是 arm64,因運維複用舊名。把這三類信號納入每日站會看板,比只看“構建紅綠”更早止損。跨港日韓新美節點時,用同一套檢測腳本輸出提交到 infra 倉庫,避免區域腳本分叉。把“本迭代禁止合併新的 vendored Intel 切片”寫進合併策略,可減少回滾半徑。若團隊仍混用 Intel 筆記本與 ARM CI,提醒開發者在本地也跑一遍 arm64-only 配置,減少“我電腦能過”噪聲。
- 鏈接錯誤:arm64 未定義符號與仍存在的 x86_64 切片並存。
- 模擬器漂移:YAML 目的地與新 Xcode 鏡像不一致。
- 標籤謊言:隊列名與真實架構不符。
xcodebuild build 牆鍾力爭下降 ≥ 35%;刪除 Intel 容量前至少觀察雙隊列 14 天。
二進制清點:先證明還有 x86_64 再罵 Swift
遍歷 .framework、.a、預編譯 XCFramework,以及 Carthage/Build、Pods/、ThirdParty/。遷移工單應粘貼兩條命令:
find . \( -name "*.framework" -o -name "*.a" -o -name "*.xcframework" \) -print0 | xargs -0 -I@ sh -c 'echo "@:"; lipo -info "@" 2>/dev/null || file "@"'
(若複製請保持 XCFramework 擴展名連續無空格。)發現供應商仍只發 Intel 切片時,走商務升級而不是用 EXCLUDED_ARCHS=arm64 把 Rosetta 悄悄塞回工程。在共享租賃主機上把清點腳本集中到單一倉庫,保證日本與美國節點輸出可 diff,否則“東京綠弗吉尼亞紅”會無限繁殖。對每類二進制記錄供應商工單號與承諾日期,避免口頭“下週修”。若短期必須保留 Intel 切片,明確標註為臨時豁免並設到期自動告警。
Runner 矩陣:Intel 車道與 ARM 車道的職責
過渡期每條車道要有顯式承諾,不要假裝“同一套 CI”。
| 維度 | ARM64 主車道 | Intel 斷路車道 | 備註 |
|---|---|---|---|
| 主要受眾 | 默認 PR、模擬器測試、TestFlight Archive | 等待供應商刷新的二進制、偶發對比 | 斷路車道不應承擔長期簽名主路徑 |
| 工具鏈假設 | 原生 arm64 CLI | 可容忍 Rosetta 的舊腳本 | 記錄 file $(which node) 防混用 |
| 觀測窗口 | 每日耗時與 flake 率 | 僅驗證兼容性迴歸 | 指標寫入同一 Grafana 板 |
xcodebuild 與構建設置:應寫成策略的項
把下列項固化到共享 xcconfig 或 Fastlane 環境導出——爭論一次,處處繼承。
| 設置項 | ARM64 CI 推薦值 | 備註 |
|---|---|---|
ARCHS |
arm64 |
顯式優於“標準”,scheme 間 app 與擴展常不一致。 |
ONLY_ACTIVE_ARCH |
Release 風格 CI 用 NO;內環 Debug 可 YES。 |
不一致會表現為設備與模擬器差異抖動。 |
EXCLUDED_ARCHS[sdk=iphonesimulator*] |
Apple Silicon 主機通常留空 | 移除誤傷 arm64 模擬器構建的舊排除項。 |
標誌需與固定的 DEVELOPER_DIR 配對,參見 xcode-select 矩陣指南;兩套 Xcode 解釋同一工程差異是遷移覆盤裡最常見的噪聲源。
CocoaPods、SwiftPM 與抗拒 ARM64 的二進制圖
CocoaPods 用戶應在 arm64 主機上重生 Pods/,不要從 Intel rsync。SwiftPM 團隊要核對 Package.resolved 裡二進制目標是否含 arm64-apple-ios。供應商落後時考慮臨時源碼構建或 fork pin;利息按天累積。
uname -m 顯示 arm64 但 file $(which node) 報 x86_64 時,OpenClaw 或 JS linter 可能在翻譯模式下燒 CPU 並汙染崩潰日誌。
雙隊列調度:隊列深度、內存與磁盤
Apple Silicon Mac mini 在 16 GB 上同時跑三路重型 Archive 加 UI 測試會現形。遷移期按實測內存壓力限制每主機併發 xcodebuild,用不同標籤區分“僅編譯 ARM”與“ARM Archive”池。ARM64 不會縮小 DerivedData;把遷移與 DerivedData 隔離 一起做,避免實驗互相驅逐緩存。
八步切換清單(可貼進 Jira)
- 切換週末前 72 小時凍結依賴升級。
- 每臺區域主機跑清點腳本,輸出 diff 提交 infra。
- 將 xcconfig 策略應用到含擴展的所有 scheme。
- 在 arm64 乾淨檢出上重裝 Pods/SwiftPM。
- 啟用雙隊列,同種子對比牆鍾、flake、產物大小。
- 默認 PR 路由切 ARM64,Intel 車道只讀保留。
- 觀察 14 天;若失敗飆升,回滾標籤而非密鑰。
- 下線 Intel 或降級為帶計費標籤的專項作業。
指標表:租賃 M4 上何謂成功
| 指標 | Intel 基線(示例) | ARM64 目標 |
|---|---|---|
| 乾淨構建 p50 | 19.5 分 | 同提交 12.0 分或更好 |
| 模擬器 UI 測試 p95 | 41 分 | 目的地規範化後 28–33 分 |
| 周電力成本代理 | 1.00(歸一) | 空閒瓦特與吞吐綜合 0.62–0.78 |
請用自家 Grafana 或 Buildkite 導出替換示例數——遷移 deck 不應沒有原始直方圖。
常見問題:Rosetta、模擬器與簽名
| 問題 | 實操答案(2026-04-30) |
|---|---|
| CI 是否應跑在 Rosetta 下求快? | iOS 編譯否——原生 arm64 工具鏈勝;Rosetta 僅給遺留輔助工具。 |
| 是否需要按架構拆分簽名身份? | 身份不按架構分,但描述文件與權利須匹配實際產物;圖變更後重導。 |
簽名自動化細節見 鑰匙串與描述文件 CI。
為何裸金屬 Mac mini M4 仍贏得遷移賭注
ARM64 CI 不只關乎主頻,而是確定性工具鏈行為,避免虛擬機撒謊。租賃 Mac mini M4 配 1–2 TB NVMe 讓你能跑雙隊列、保留多棵 DEVELOPER_DIR 樹,並在工程師其他時區睡覺時吸收 DerivedData 峰值。餘量把遷移從嚇人 flag day 變成可度量、可回滾的發佈——再配透明 定價 解釋為何加第二臺而不是壓垮第一臺。合規若需目視確認,偶用 VNC;日常遷移應留在可 grep 的 SSH 日誌裡。