VPSSpark 部落格
← 返回開發日記

iOS CI 構建時間優化:GitHub Actions + Xcode 從 28 分鐘降到 9 分鐘

機房手記 · 2026.06.06 · 約 10 分鐘閱讀

開發者在 MacBook 前查看 iOS CI 構建速度優化結果
每次推程式碼都要等 28 分鐘——拆開時間軸後,才看清時間花在哪裡。

在 GitHub Actions + Xcode 的典型 iOS 專案中,iOS CI 建置時間慢常被誤以為是常態。真正的癥結在於:iOS CI slow ≠ Xcode slow,而是 pipeline 無狀態、沒快取、又採直列設計

本文以 8 人 iOS 團隊的真實案例(Swift 約 46 萬行、28 個 Pods、14 個 SPM、日均 30+ push)為基礎,將 GitHub Actions macOS CI 從 28 分鐘優化到 9 分鐘,附上完整的 iOS CI optimization 方案。

28→9
平均建置時間(分鐘)
68%
總壓縮比
74%
來自快取 + 並行

一、問題定義:為什麼 iOS CI 會慢?

多數團隊習慣接受 20–30 分鐘的等待。根因不在 Xcode,而在 CI pipeline 的結構設計。

1.1 GitHub Actions CI 的本質問題

GitHub Actions macOS runner 是 ephemeral environment(臨時環境)。每次執行都會導致:

  • ❌ DerivedData 遺失(無法 incremental build)
  • ❌ CocoaPods 每次重新 install
  • ❌ SPM 每次重新 resolve
  • ❌ build context 無法複用

結果:每次都是 cold build。

1.2 基線建置時間拆解(28 分鐘)

workflow_dispatch 冷跑 3 次取中位數,拆分各階段耗時:

階段耗時類型
Checkout45s固定
pod install3m 12s網路依賴
SPM resolve1m 44s解析
xcodebuild build11m 08scold compile
xcodebuild test6m 22sCPU
xcodebuild archive5m 30s直列阻塞
upload/sign1m 05s固定
Total29m 46s

核心瓶頸:iOS CI 慢的三大原因

  1. Cold Build(39%)——沒有 DerivedData,每次全量編譯 46 萬行 Swift
  2. Dependency Re-resolve(17%)——Pods + SPM 每次重新下載/解析
  3. Serial Pipeline(19%)——test 與 archive 無依賴卻直列執行

二、優化目標與結果

優化結果(iOS CI optimization 總覽)

階段建置時間
baseline28 min
+ cache20 min
+ parallel12 min
+ Apple Silicon9 min

優化收益拆解

  • Cache:42%(約 8 分鐘)
  • Parallelization:32%(約 6 分鐘)
  • Apple Silicon:26%(約 3 分鐘)

案例背景(E-E-A-T)

參數
Swift 程式碼量約 46 萬行(含測試)
CocoaPods / SPM28 Pods + 14 packages
基準 RunnerGitHub macos-latest(Intel,4 核)
團隊/頻率8 人,日均 30+ push
量測方法每步加時間戳,冷跑 3 次取中位數

單變數實驗(各配置獨立跑 10 次取中位數):僅加快取 -29%、僅拆並行 -21%、僅換 Apple Silicon -18%。結構優化(快取 + 並行)貢獻 74%,硬體是加速上限而非第一因素。 p95 從 33 min 降至 12 min,DerivedData 命中率 80%。

三、優化方案一:CI 快取(最大收益)

3.1 為什麼快取是關鍵

iOS CI optimization 的本質是:讓 Xcode incremental build 在 CI 中重新生效。 必須把 DerivedData、CocoaPods cache、Swift Package Manager cache 三個目錄持久化。

3.2 快取三要素

  • DerivedData~/Library/Developer/Xcode/DerivedData
  • CocoaPods cache~/Library/Caches/CocoaPods
  • SPM cache~/.spm-cache

3.3 GitHub Actions 設定

.github/workflows/ios-ci.yml(DerivedData + CocoaPods + SPM 快取)
- name: Cache DerivedData
                  uses: actions/cache@v4
                  with:
                    path: ~/Library/Developer/Xcode/DerivedData
                    key: deriveddata-${{ runner.os }}-${{ hashFiles('**/Podfile.lock','**/Package.resolved') }}

                - name: Cache CocoaPods
                  uses: actions/cache@v4
                  with:
                    path: ~/Library/Caches/CocoaPods
                    key: pods-${{ runner.os }}-${{ hashFiles('**/Podfile.lock') }}

                - name: Cache SPM
                  uses: actions/cache@v4
                  with:
                    path: ~/.spm-cache
                    key: spm-${{ runner.os }}-${{ hashFiles('**/Package.resolved') }}

3.4 快取 key 設計要點

快取命中率決定 DerivedData cache 能否真正生效。key 設計有三個常見層級:

key 策略命中率問題
只用 runner.os~100%可能命中舊 Pods,產物不一致
鎖檔雜湊(推薦)~80%依賴不變就命中,更新才重建
包含 commit SHA~0%每次 push 都 miss,等於沒快取

建議用 Podfile.lock / Package.resolved 雜湊作為主 key,並設定 restore-keys 前綴比對:主 key miss 時仍能拿到上一次有效快取,觸發增量編譯而非完全 cold build。CI 裡務必用 pod install --no-repo-update,避免每次改寫 lock 檔導致快取失效。

詳見 GitHub Actions cache 文件;macOS runner 排隊問題可參考 GitHub Actions macOS runner 為什麼總在排隊

3.5 快取效果

項目優化前優化後
pod install3m 12s50s
SPM resolve1m 44s15s
build11m3–4m

平均節省 8–10 分鐘。

四、優化方案二:CI 並行化(Pipeline optimization)

4.1 問題

預設 CI:build → test → archive(直列)。但 test 和 archive 沒有依賴關係,可以並行執行。

4.2 並行 Job 設計

.github/workflows/ios-ci.yml(test / archive 並行)
jobs:
                  build-and-test:
                    runs-on: macos
                    steps:
                      - run: xcodebuild build test

                  archive:
                    runs-on: macos
                    if: github.ref == 'refs/heads/main'
                    steps:
                      - run: xcodebuild archive

archive 只在 main 觸發;各 job 獨立還原快取。憑證用 Fastlane Match 管理。高頻 CI 的資源隔離可參考 3 台 Cloud Mac 撐住每天 500 次 iOS CI

4.3 效果

模式時間
serial20 min
parallel12 min

節省 5–7 分鐘。

五、優化方案三:Apple Silicon Runner

5.1 為什麼要放最後

硬體不是解決 iOS CI slow 的第一因素。 沒快取時換 Apple Silicon 僅省 18%;結構優化完成後再升級,才能從 12 min 壓到 9 min。

5.2 實測提升(快取 + 並行已開啟)

階段IntelApple Silicon
build3m 40s1m 55s
test6m 22s3m 48s
archive5m 30s3m 10s

5.3 結論

額外節省 3–5 分鐘。 Apple Silicon 在 Swift 編譯和連結階段提速最明顯,參見 Apple 增量建置文件

5.4 三種 macOS Runner 方案比較

結構優化完成後,團隊通常在三類 GitHub Actions self-hosted runner macOS 方案中選擇:

方案建置時間佇列維護成本
GitHub macos-latest~20 min高(尖峰等 10–20 min)
自建 Mac mini(Intel)~14 min
Cloud Mac(Apple Silicon)~9 min

GitHub 託管 runner 免費但有佇列瓶頸,且快取儲存受 10 GB/repo 限制,大型專案容易頻繁 evict。自建可消除佇列但 Intel 硬體有天花板。對於日均 30+ push 的團隊,獨享 Apple Silicon 節點通常 ROI 更高——結構優化自己做,硬體和佇列問題再單獨評估。

六、iOS CI optimization 決策樹

iOS CI pipeline optimization checklist
CI > 15 min?
                  ↓
                cold build > 40%?
                  → YES: enable cache (DerivedData + Pods + SPM)
                  ↓
                pipeline serial?
                  → YES: split jobs (test / archive)
                  ↓
                still slow?
                  → upgrade Apple Silicon runner

可複現 Runbook(5 步):

  1. 建立基線:每 step 加 echo "::notice::$(date -u +%H:%M:%S)",冷跑 3 次取中位數
  2. 加快取:DerivedData + Pods + SPM,連跑 10 次統計命中率(目標 > 60%)
  3. 拆 workflow:test / archive 獨立 job,archive 僅 main 觸發
  4. 評估硬體:結構優化後仍 > 12 min 再考慮 Apple Silicon runner
  5. 監控 p95:目標 ≤ 1.5× 均值,超基線 20% 告警

七、常見誤區(iOS CI Optimization Mistakes)

❌ Xcode incremental build in CI works automatically

錯誤。CI 沒有 DerivedData,必須顯式快取。

❌ upgrade Mac solves CI slow

錯誤。未快取情況下提升有限(約 18%)。

❌ increase -jobs always faster

超過 CPU core 會變慢。M2 建議 -jobs 6~8

❌ cache key should be exact

commit SHA 會導致 cache miss。用 Podfile.lock / Package.resolved hash。

八、FAQ(GitHub Actions iOS CI 高頻問題)

Q1:為什麼 GitHub Actions iOS CI 很慢?

因為 GitHub Actions macOS runner 是 stateless ephemeral environment,不保留 DerivedData、Pods 或 SPM 快取。本機有熱快取,CI 每次從零 cold build,即使本地 Xcode build time 很快。

Q2:iOS CI optimization 最有效方法是什麼?

快取 DerivedData + CocoaPods + SPM,貢獻 42%,平均節省 8–10 分鐘。這是 Xcode build time optimization 在 CI 環境裡的第一優先級。

Q3:Apple Silicon 能解決 CI slow 嗎?

不能單獨解決,只是加速上限。沒快取時僅省 18%;配合快取和並行化後,才能將建置時間從 12 min 壓到 9 min。

Q4:Pods 和 SPM 哪個更慢?

CocoaPods 通常更慢(3m 12s vs 1m 44s),因為涉及網路下載。兩者都應快取,收益疊加。

Q5:最佳優化順序?

Cache → Parallelization → Apple Silicon。三步組合壓縮 68%,順序不可跳步。

九、結論

iOS CI 慢的本質不是效能問題,而是:

CI pipeline 沒有複用任何歷史計算結果
最優路徑:① Cache(最大收益)→ ② Parallelization(結構優化)→ ③ Apple Silicon(效能上限)。

補充:完成結構優化後,若需獨享 Apple Silicon self-hosted runner 且不想自己維護硬體,可參考 Cloud Mac 方案(佇列零等待、快取不受 10 GB/repo 限制)。

限時特惠

iOS CI 提速最後一塊:Apple Silicon Cloud Mac

獨享算力 · 按月訂閱 · 無需維護硬體

返回首頁
限時優惠 查看方案