DevOps / CI/CD

SwiftPM 私有依賴:2026 年遠端 Mac 配置指南

SwiftPM 私有依賴:2026 年遠端 Mac 配置指南

獲勝者是「專用倉庫憑據+固定 Package.resolved+實際構建使用者的 SSH 設定」;只要遠端 Mac 會執行 xcodebuild、定時任務或自動歸檔,就應先單獨驗證依賴解析,再接入完整構建,不能把個人 Xcode 的登入狀態當成 CI 設定。

這篇文章適合三類讀者:正把本地 Mac 遷移到遠端構建環境、專案含有私有 Swift 包的獨立開發者;使用命令列或定時任務執行 iOS 構建的人員;以及需要管理多個私有倉庫、重視權限隔離與密鑰輪換的小團隊。

先分清楚:開發者憑據,還是構建憑據

常見失敗案例是:Xcode 圖形介面可以正常解析並構建,但同一台遠端 Mac 的背景任務卻無法拉取私有包。原因通常不在 Swift 程式碼,而在兩個會話使用了不同的 macOS 使用者、SSH 設定或 Keychain 狀態。

遷移前先把專案依賴畫出來:

  • 列出專案直接引用的私有 Swift 包。
  • 展開傳遞依賴,確認每個私有倉庫的實際來源。
  • 記錄目前可成功構建的 Package.resolved 與提交版本。
  • 確認每個倉庫只需要讀取權限,還是確實需要寫入權限。
  • 將個人開發帳戶與遠端構建專用帳戶分開。

Apple 的 Swift Package 持續整合官方說明 明確把憑據提供與依賴鎖定視為 CI 環節的一部分。這代表「在本地可以拉到」並不等於「在背景任務可以拉到」。

判斷維度 個人開發憑據 遠端構建專用憑據
使用者 開發者本人 實際執行構建的 macOS 使用者
權限 可能包含多個專案與寫入權限 只讀取指定私有倉庫
使用位置 本地 Xcode、互動式終端機 遠端 Mac 的命令列與自動任務
撤銷方式 撤銷可能影響日常開發 可單獨停用,不牽連個人工作
風險 容易被複製到腳本或共享主機 範圍較小,便於輪換與稽核

私人包的宣告仍應以專案的 Package.swift 和 Apple 的 Package.Dependency 官方文件 為準。這一步不是 SwiftPM 入門,而是為後續授權測試建立清單。

兩條配置路徑:圖形登入不等於 SSH 可用

Swift Package 私有倉庫如何配置認證,關鍵不在於先開啟 Xcode,而在於先確認「誰」會執行讀取動作。假設自動任務由構建使用者執行,SSH 私鑰、主機公鑰和 known_hosts 都必須在該使用者可讀取的環境中完成配置。

配置項目 建議做法 不建議做法
私鑰 為遠端構建建立專用 SSH 密鑰 直接複製開發者日常私鑰
公鑰 加到指定私有倉庫的唯讀授權位置 授予整個帳戶的管理權限
主機校驗 預先建立並審查 known_hosts 以關閉主機校驗掩蓋錯誤
執行使用者 使用後台任務實際使用的 macOS 帳戶 只在管理員或個人帳戶測試
密鑰保存 由 SSH agent 或受控 Keychain 管理 寫入程式碼、腳本或終端機歷史

若倉庫使用 SSH Git URL,先依照 GitHub 官方 SSH 密鑰與 agent 說明 建立專用密鑰,再由倉庫端加入公鑰。文件中的 ssh-keygenssh-add 是認證配置的兩個關鍵參數,私鑰內容本身不應出現在文章、腳本或共享筆記中。

接著使用同一個構建使用者測試倉庫連線。可參考 官方 SSH 連線測試方法;若測試主機名稱、帳戶或指紋不符,應在這裡停止,不要直接進入 Xcode 構建。

首次解析與 Package.resolved:固定版本,先於編譯

Package.resolved 是否應該提交到倉庫?對需要可重現 CI 的專案,應將它納入版本控制,並在每次有意更新私有包時一併審查。Apple 的 SwiftPM 持續整合文件 將提交解析檔列為 CI 的重要做法;遠端環境不應在沒有審查的情況下自行選擇新版本。

第一輪不要直接執行完整 Archive。建議按照以下時間線操作:

  • 建立乾淨工作目錄:使用與後續任務相同的專案路徑和構建使用者,避免把個人快取當成成功條件。
  • 確認檔案位置:檢查 Package.resolved 是否位於專案實際使用的位置,並確認檔案已提交。
  • 單獨解析依賴:先使用 xcodebuild -resolvePackageDependencies。這個參數只針對依賴解析,能把認證、主機校驗和版本衝突分開。
  • 觀察解析結果:確認私有包來源、版本與提交資訊符合基線。不要只看命令是否結束。
  • 解析失敗即停:認證失敗先回到 SSH;主機校驗失敗先檢查 known_hosts;版本失敗才檢查 Package.resolved 與依賴宣告。

xcodebuild -resolvePackageDependencies 的用途與命令列構建邏輯,可對照 Apple TN2339 命令列構建技術說明。若依賴解析階段已經失敗,繼續編譯只會製造更難分辨的錯誤訊息。

解析結果 可觀察證據 下一步
認證成功 私有來源可讀取,解析檔未被意外改寫 進入編譯測試
主機校驗失敗 出現未知或不匹配的主機指紋 停止,審查 known_hosts
版本解析失敗 解析檔與依賴宣告不一致 審查提交與版本規則
找不到私有包 URL、權限或 SSH 設定不符 回到倉庫授權測試
只在 Xcode 成功 圖形會話帶有額外登入狀態 改用構建使用者重測

xcodebuild 為什麼無法拉取私有依賴

xcodebuild 無法拉取私有依賴,通常是因為它執行在另一個使用者、另一個環境變數集合,或另一個工作目錄。圖形介面曾經成功登入,只能證明那個互動式會話具備存取條件。

實際命令應與後續自動任務一致。不要在終端機中臨時載入密鑰後,卻用另一套定時任務設定作結論。最低限度要核對:

  • 構建使用者是否與 SSH 測試使用者相同。
  • SSH Git URL 是否與專案依賴來源一致。
  • known_hosts 是否由該使用者可讀取。
  • Package.resolved 是否已提交且沒有被解析過程意外更新。
  • 是否使用了不同的 HOME、工作目錄或 SSH agent。
  • 代理、URL 映射或系統 Git 設定是否只存在於互動式 Shell。

若專案確實需要系統 Git 的代理、URL 映射或進階 SSH 設定,再評估 xcodebuild 的 SCM 選項;不要先加入一長串參數。Apple 的 xcodebuild 源程式碼管理說明 應作為參數行為的核對來源;若頁面路徑或適用版本有所變化,應以寫作時的 Apple 官方文件為準。

實務上,失敗日誌至少要能回答三件事:使用哪個 macOS 使用者、在哪個工作目錄執行、失敗發生於認證還是版本解析。日誌可以保留錯誤類型與命令返回結果,但不得輸出私鑰、存取令牌或完整敏感環境變數。

從解析到 Archive:以同一個會話完成驗收

完成解析後,才進入第一次命令列構建。此時的目標不是追求最快,而是證明圖形介面以外的環境也能完成整條路徑。

建議按以下順序驗收:

  • 先構建指定 Scheme:使用與後續自動任務相同的 Scheme、目的地和工作目錄。
  • 核對私有包目標:確認私有包被解析、編譯,且其產品確實被主程式連結。
  • 產生 Archive:使用 xcodebuild archive 與明確的 -archivePath,避免只得到散落的構建產物。
  • 檢查歸檔內容:確認 Archive 包含預期 App、版本資訊和簽名所需內容。
  • 再處理匯出:若流程需要 IPA 或其他發佈產物,使用 -exportArchive 與受控的 -exportOptionsPlist
  • 保留失敗脈絡:記錄命令、使用者、工作目錄、解析結果與歸檔結果,讓下一次能重現。

-archivePath-exportArchive-exportOptionsPlist 都是命令列歸檔流程中的具體參數,使用方式可對照 Apple 官方歸檔與匯出文件。這些參數不是固定填充值;路徑、Scheme 和匯出設定必須取自實際專案,不能照抄範例中的假路徑。

私有包讀取憑據也不應自動擁有發佈權限。程式碼簽名憑據、App Store Connect 存取權與倉庫 SSH 密鑰應分開管理。需要進一步處理構建憑據的讀者,可先參考 ProxyMac 的使用說明,再按專案權限模型配置。

無人值守構建:SSH agent、Keychain 與環境變數分開測

SwiftPM 私有依賴如何用於無人值守構建,答案不是「讓 VNC 視窗一直開著」,而是驗證 SSH agent、Keychain 和環境變數在沒有圖形會話時仍然成立。

交給定時任務前,先完成三種會話測試:

  • SSH 連線保持期間執行一次解析。
  • 斷開 SSH 連線後,由背景任務重新執行解析。
  • 不開啟 VNC 或 Xcode 登入狀態,直接執行構建與 Archive。

若 SSH 密鑰帶有口令,應確認 agent 的生命週期與載入方式。可參考 GitHub 官方 SSH 口令與 agent 文件。不能把口令硬編碼進腳本,也不能為了讓任務「成功」而永久關閉主機校驗。

失敗時要有明確停止條件:

  • 密鑰過期或被撤銷:停止解析,通知輪換。
  • known_hosts 不匹配:停止連線,人工核對主機身分。
  • 私有倉庫被移除:停止構建,不自動改用公開鏡像。
  • 構建使用者變更:重新配置並完成完整驗收。
  • Xcode 或 SwiftPM 更新:重新執行乾淨解析與 Archive。

這種隔離也能避免倉庫讀取權限意外變成發布權限。對小團隊而言,構建任務的成功不應以犧牲密鑰邊界換取。

重啟與依賴更新後的回歸清單

遠端 Mac 重啟後 SSH 密鑰失效怎麼辦?先判斷是密鑰沒有載入、agent 沒有在背景會話存活,還是構建使用者讀不到 Keychain。不要直接重新產生密鑰,更不要把私鑰複製到另一個帳戶。

重啟後應從乾淨工作目錄重跑:

  • 以構建使用者執行 SSH 倉庫存取測試。
  • 單獨執行依賴解析,核對 Package.resolved
  • 執行實際 Scheme 的命令列構建。
  • 產生 Archive,檢查歸檔產物。
  • 以無 VNC、無互動式登入的方式重做一次。
  • 將結果與重啟前的日誌比較。

私有包升級也要遵循同一邏輯:先在可審查的分支更新解析結果,確認 Package.resolved 的變更,再讓遠端 Mac 執行構建。不要讓背景任務自行漂移到新版本。

若專案之後要接入長期 iOS 打包流程,建議先在 ProxyMac 的遠端使用支援頁面確認連線與帳戶操作,再安排冷啟動驗收。需要比較不同租用週期時,可查看 ProxyMac 的方案頁面;選擇前仍應以實際構建時數、是否需要常駐和團隊權限要求為準。

本地臨時工作站若把個人 Xcode 登入、私有倉庫密鑰和簽名憑據混在一起,常見缺點是權限難以收回、重啟後狀態不透明,還會讓背景任務依賴某個人的互動式會話。改用一般雲端編譯環境,則可能受限於自訂 SSH、Keychain 或完整 macOS 工具鏈的控制範圍。對需要真實 macOS、完整 root 權限與可自行驗收的團隊,租用 ProxyMac 的遠端 Mac 會比臨時拼接這些環節更容易維持一致;但若工作負載長期滿載或必須直接連接實體裝置,自購 Mac 仍可能更合適。

較穩妥的做法,是先用短週期遠端 Mac 讓真實專案完成冷啟動解析、Archive 與重啟復驗。只有在脫離圖形會話後仍能穩定讀取私有依賴,才把該主機接入長期無人值守的 iOS 打包任務。

為私有依賴配置可靠的遠端 Mac

使用 ProxyMac 獨享 M4 Mac mini,讓命令列建置、測試與歸檔流程在穩定的實體算力上持續運行。
透過 SSH 或瀏覽器 VNC 遠端存取完整 macOS 環境,方便你按部署流程檢查授權、套件鎖定與建置結果。