寫給負責合併與發佈的人

把下一次合併交給專屬建置節點

先手動產出一份可驗證的 ipa,再交由 CI 執行任務。本指南依照開機、連線、接入、發佈與日常管理安排步驟,不必先重寫現有 CI 流程。

以一小時內完成初步接入為目標,並非交付時限承諾;大型依賴下載、Xcode 安裝及簽章材料準備都會影響所需時間。已有節點可直接從連線檢查開始。

開機前,先備妥所需資訊

先啟用一台符合目前專案需求的節點

如果只是偶爾打包,而且已有閒置的 Mac,繼續自行架設可能更省;如果每天要合併多次,又不想自行顧電源、網路與散熱,可以考慮獨享託管。OSXPort 提供整台實體 Mac mini,每個節點只供一位客戶使用,並非虛擬機。

  1. 01

    確認專案基準

    準備一條可重現的建置指令、程式碼存取方式、Xcode 版本需求及依賴鎖定檔。先選定一個 App、一個 scheme 和一個分支,別讓首次接入演變成整套發佈系統遷移。

  2. 02

    選擇規格與租期

    在訂購頁選擇機型、區域及按日/週/月/季計費的租期。Port M4 Base 適合輕量測試;多分支建置與模擬器工作可優先評估 Port M4 Plus;大型多 target 專案則可評估 Port M4 Pro。

  3. 03

    保存交付資訊

    完成訂單後,前往控制台查看節點位址、登入使用者名稱及憑證。節點實際可用狀態以控制台即時顯示為準。請將節點識別碼登記在團隊資產清冊中,勿將登入密碼寫入程式碼儲存庫或工單內容。

  4. 04

    選擇合適的區域

    可選區域:新加坡、日本(東京)、韓國(首爾)、香港、美國西部。除了團隊所在地,也要考量程式碼儲存庫與依賴來源的位置;跨區網路的實際效能,請以自身的下載與上傳工作驗證。

三種規格分別為 Apple Silicon M4 · 16GB 統一記憶體 · 256GB SSD、Apple Silicon M4 · 24GB 統一記憶體 · 512GB SSD,以及 Apple Silicon M4 Pro · 64GB 統一記憶體 · 2TB SSD。首次測試不建議一開始就提高並行數,請先記錄單次建置的記憶體、磁碟用量及產物大小。

先確認機器,再接入 CI 流程

讓同一個使用者負責登入、編譯與匯出

首次連線時,先核對節點位址與使用者,再檢查開發工具。以下是示範工作階段,並非即時節點輸出;版本號僅供格式參考,請以目前節點的實際執行結果為準。

分三層檢查,不必急著重裝環境

連線層:使用控制台提供的位址、連接埠和使用者名稱連線。首次連線時,請核對主機指紋;若指紋意外變更,先確認節點是否已更換,不要直接略過驗證。若連線逾時,先檢查位址與網路;若驗證遭拒,再檢查使用者及憑證。

工具層:使用 xcode-select -p 確認目前的開發者目錄,再用 xcodebuild -version 記錄版本。如果專案需要其他版本,先確認該版本已安裝,再明確切換路徑。

專案層:在專案目錄安裝鎖定版本的依賴,先手動執行現有的建置指令。互動式登入成功,不代表背景 runner 也能存取簽章材料;之後務必以 runner 實際使用的帳號再驗證一次。

範例中的 NODE_USER 和 NODE_ADDRESS 請設為控制台提供的值;App.ipa 是範例產物名稱。若專案使用 Bundler 管理 fastlane,請依專案慣例使用 bundle exec fastlane gym。

osxport · tokyo-node
$ ssh "$NODE_USER@$NODE_ADDRESS"
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
$ xcodebuild -version
Xcode 16.4
Build version 16F6
$ cd ~/workspace/App
$ fastlane gym
Creating archive
Exporting archive
Successfully exported and compressed dSYM file
Successfully exported and signed the ipa file
Exported ipa: ./build/App.ipa
$ ls -lh ./build/App.ipa

驗收項目:遠端指令成功結束、版本符合專案需求、產物路徑存在。若簽章或編譯失敗,請保留第一個錯誤前後的日誌,不要只截取最後一行。

沿用團隊現有的 CI

註冊執行器前,先手動跑通一項任務

三種接入方式都在同一台 macOS 實體節點上執行。以下建議的人數不是容量保證;並行數應依單次建置的記憶體用量、同時執行的模擬器數量及磁碟使用量決定。

GitHub Actions 自架 runner

適合:約 3~15 人、已透過工作流程檔協作的團隊。無須另建排程系統,只要將節點登記到受控儲存庫或組織即可。

  1. 從儲存庫或組織設定取得適用於目前 macOS 與晶片架構的 runner 安裝套件及註冊指令。
  2. 使用專用執行帳號完成註冊,新增團隊自訂標籤,並將工作流程的 runs-on 設為該標籤。
  3. 先執行版本檢查和不含敏感資訊的建置任務,再設定背景服務、密鑰注入與產物上傳。

不建議:將含有簽章材料的節點開放給不受信任的外部合併請求。獨享主機不代表各工作流程彼此隔離。

查看執行器驗收項目

GitLab Runner · shell executor

適合:約 3~30 人、程式碼與權限管理已集中在 GitLab 的團隊。shell executor 會直接使用節點上的 Xcode 與命令列環境。

  1. 安裝適用於 macOS 的 GitLab Runner,並使用專案或群組提供的註冊資訊登記執行器。
  2. 選擇 shell executor,設定專用標籤,並限制可執行的受保護分支及任務範圍。
  3. 將依賴還原、編譯、匯出與產物儲存拆成可分別驗證的階段,先從單一任務並行開始。

不建議:在同一個 shell 執行器上混跑彼此不受信任的客戶儲存庫;工作目錄與主機權限都需要自行管理。

查看執行器驗收項目

Jenkins agent

適合:約 10~30 人、已有 Jenkins 控制器和發佈審核流程的團隊。將節點加入為 macOS agent,無須遷移整套 CI 流程。

  1. 在控制器建立獨立的 agent,指定節點標籤、專用工作目錄及執行帳號。
  2. 依控制器設定建立連線,確認所需 Java 版本與 agent 執行環境相容,再啟用常駐執行。
  3. 讓測試任務明確選用 macOS 標籤,並檢查環境變數、工具路徑及產物封存權限。

不建議:只為偶爾打包一次就新建控制器。若已有輕量 CI,通常無須增加另一項管理工作。

查看執行器驗收項目

執行器顯示在線後,還要通過這四項檢查

請以 runner 實際使用的帳號驗證,不要只在個人的互動式工作階段中測試。
檢查項目驗證方式通過條件
工作目錄與工具執行 whoami、pwd 和 xcodebuild -version使用者、目錄及 Xcode 版本均符合任務設定
儲存庫與依賴存取使用 CI 注入的受限憑證擷取指定分支,並依鎖定檔還原依賴不依賴個人終端機中未明確設定的權杖或路徑
簽章可用性在非互動式任務中完成封存與匯出不會出現等待人工確認的對話框,憑證不會寫入日誌
重新連線與保存產物檢查背景服務狀態,並在任務完成後取回產物與日誌執行器可恢復連線,產物不只留在暫存工作目錄

同一節點可以註冊多個受控任務入口,但所有入口仍共用 CPU、統一記憶體和 SSD。先將並行數設為一項建置,再依實際測量逐步增加;多個 runner 名稱不會增加實體資源。

在 Windows 寫程式,在 macOS 打包

將 Flutter 的 iOS 階段留在遠端執行

Windows 可用於撰寫程式、提交程式碼與查看日誌;iOS 編譯和簽章仍會在雲端 Mac 上執行。獨享節點無法取代有效的 Apple 開發者計畫資格、簽章憑證、私鑰,以及與 App 相符的描述檔。

  1. 01

    固定依賴

    同步相同的提交版本與鎖定檔,確認 Flutter、Dart、CocoaPods 和 Xcode 彼此相容。先執行 flutter doctor -v 檢查工具鏈,再執行 flutter pub get;不要將另一台電腦上的絕對路徑帶進專案。

  2. 02

    匯入簽章材料

    透過團隊核准的安全方式傳送憑證、私鑰及描述檔。在實際建置帳號可存取的專用鑰匙圈中匯入憑證,設定描述檔與匯出選項;確認 bundle identifier、團隊識別碼及目標發佈類型彼此相符。

  3. 03

    執行並取回產物

    執行 flutter build ipa --release;若專案需要指定匯出規則,請傳入相應的 --export-options-plist。產物通常位於專案的 build/ios/ipa/,但請以實際輸出為準,再由 CI 封存到團隊的產物儲存空間。

  4. 04

    釐清測試範圍

    遠端可執行模擬器測試與自動化建置;涉及實體裝置、感測器及互動體驗的驗證,仍應在裝置端進行。React Native 團隊也可以將 iOS 編譯階段移到節點上執行,但必須依專案自己的指令還原依賴。

快取是加速工具,不是備份。請依專案、Xcode 版本及依賴鎖定檔設計快取鍵;簽章異常時,先檢查有效期限、私鑰與描述檔是否相符,不要一開始就刪除所有建置快取。

先確認能匯出,再設定上傳

分開管理發佈憑證與節點登入憑證

透過 TestFlight 發佈前,App 必須已在 App Store Connect 完成必要設定,且具備相應的發佈權限。API Key 用於授權上傳,無法取代編譯所需的簽章憑證與描述檔。

設定步驟

  1. 確認產物可安裝。先使用 fastlane gym 或專案既有指令完成封存與匯出,並確認 bundle identifier、版本號及建置號。
  2. 準備 API Key。由具備權限的負責人建立角色適當的 App Store Connect API Key,記錄 Key ID、Issuer ID,並妥善保管私鑰檔案。
  3. 注入 CI。將私鑰與識別資訊存入團隊的密鑰管理系統,在任務開始時產生權限受限的設定檔,並於任務結束後移除。不要將設定檔或私鑰提交至儲存庫。
  4. 上傳並確認處理狀態。執行 pilot,核對 App 識別資訊與上傳結果。上傳成功不代表測試人員已可使用,仍須確認後續處理與測試發佈狀態。

已有 ipa 時的上傳指令

fastlane pilot upload \
  --api_key_path "$ASC_API_KEY_JSON" \
  --ipa "$IPA_PATH" \
  --skip_waiting_for_build_processing true

ASC_API_KEY_JSON 須指向依 fastlane 格式建立的臨時 API Key 設定,IPA_PATH 須指向實際 ipa。若使用 Bundler,請在指令前加上 bundle exec。

保留 App 版本、建置號、提交識別碼及上傳結果;不要將私鑰內容或完整驗證設定輸出到日誌。

上傳失敗時,依錯誤類型排查

驗證錯誤時,先核對 Key ID、Issuer ID、私鑰與角色權限;若建置號重複,先調整建置號,不必重新設定 runner;簽章或 App 識別資訊有誤,則回到封存與匯出階段。將編譯、簽章及上傳分成三個驗收點,就不必每次都從頭重跑整個流程。

將交接流程納入 CI

節點全年在線,任務仍須可遷移

節點全年 365 天持續運作。機房負責供電、網路與散熱;團隊則須管理專案依賴、密鑰、任務設定及資料備份。若發生硬體異常,請透過工單查核;不要把單一節點當成唯一且不可遺失的副本。

平時備妥可重建清單

記錄 runner 標籤、工具版本、環境變數名稱、依賴安裝流程及簽章匯入步驟。以自動化指令碼重建環境,比仰賴個人記憶更方便交接。

簽章憑證與私鑰應加密備份;建置產物與日誌應取回並存放於團隊儲存空間。DerivedData 與依賴快取可依成本決定是否備份,但必須能重新產生。

查看接入驗收清單

發生異常時,先保留資訊

記錄節點識別碼、發生時間與時區、最近一次成功的任務,以及錯誤摘要。分別說明 SSH 是否可連線、runner 是否在線、任務是否能啟動,避免只寫「打包失敗」。

若仍可登入,先匯出必要資料與日誌,再暫停新任務。工單中只提供已遮蔽敏感資訊的內容;如需授權排查,請明確說明授權範圍,不要傳送私鑰或完整密碼。

登入控制台回報異常

確認更換節點後,重新驗收

支援人員查核異常後,會透過工單確認處理方式。若需更換節點,請依交付資訊更新位址與憑證,並重新核對主機指紋。

還原依賴與簽章材料,重新註冊或連結 runner,再執行一項最小建置。確認新節點可接收任務後,撤銷舊連線憑證及不再使用的 runner 註冊。

依連線步驟重新檢查

清理日常磁碟空間前,先訂定保留政策:依發佈版本保存產物,按團隊稽核需求保存日誌,並依可重新產生的原則輪替快取。建置執行期間不要清理工作目錄或全域切換 Xcode 路徑。

將帳單與節點一併交接

發佈前確認有效期限,別只等最後一封提醒

按日租用適合首次測試或短期建置任務;按週適合階段性集中作業;按月或按季則更適合長期執行 nightly。選擇租期時應比較該租期的總價,不要直接以日租單價估算長期預算。

調整環境前,先確認權限範圍

團隊接手節點時常見的六個問題

可以安裝 Homebrew 和專案所需的依賴嗎?

可依一般 macOS 專案的方式管理開發工具與專案依賴。安裝前請檢查架構、安裝路徑及權限需求,並將版本與安裝步驟記錄在環境清冊中。首次接入時,優先重現專案既有依賴;不要同時升級所有工具,否則難以判斷問題源自專案還是環境變更。

可以自行選擇 Xcode 版本嗎?

請依專案相容性需求選擇版本,並先確認節點上已安裝的版本。若需安裝其他版本,請先檢查磁碟空間、取得方式及專案需求;不要假設特定版本一定已預先安裝。多人共用節點時,優先在任務環境中設定 DEVELOPER_DIR,避免全域切換影響其他正在執行的任務。

有 root 權限嗎?runner 需要以 root 執行嗎?

macOS 圖形介面與命令列皆可正常使用。管理員帳號及可用的 sudo 權限,請依控制台提供的憑證確認;若安裝步驟需要額外授權,請先提交工單查詢。不要將直接以 root 登入當作預設連線方式,也不建議以高權限帳號執行一般 CI 任務。建置、密鑰與工作目錄應依最小權限原則分開管理。

同一個團隊可以多人共用一台節點嗎?

可以將同一台獨享節點加入團隊工作流程,但多人共用不會增加主機的實體資源。請配置個別使用者或明確劃分任務入口、限制並行數,並約定環境變更時段。團隊須自行管理不同成員的建置與簽章權限;此節點並非彼此隔離的多租戶環境。

快取會被其他客戶清除嗎?

整台機器只供一位客戶使用,不會與其他客戶共用建置資源。不過,團隊自己的清理指令碼、磁碟管理或環境變更仍可能影響快取。請將快取視為可重建的加速層,另外備份程式碼、簽章材料與最終產物;更換節點時也應能依依賴鎖定檔還原環境。

接入卡住時,工單應附上哪些資訊?

請提供節點識別碼、CI 類型、任務的提交識別碼、發生時間與時區,以及第一個錯誤附近且已遮蔽敏感資訊的日誌。並說明同一指令在互動式終端機與 runner 中的執行結果是否相同。請刪除存取權杖、私鑰、密碼,以及敏感路徑中的業務資訊;若支援人員需要進一步排查,會透過工單與您確認授權範圍。

用一項實際任務驗收這台建置機

先按日租用試跑,再決定是否長期接手 nightly。Port M4 Base 每天 $19.7 起;保留提交識別碼、建置日誌與產物,依自身專案的實測結果選擇規格。