この記事は一点に絞ります:Flutter iOS CI/CD(主キーワード:Flutter iOS build on Mac mini)——Mac mini M4 上で flutter build ipa を安定させ、CocoaPods キャッシュ、self-hosted macOS Runner、Linux 側の Android/テスト job を分離する方法です。Flutter の本当のボトルネックは Dart ではなく、iOS ビルドチェーンの Mac 依存:pod install → xcodebuild archive → 署名 → TestFlight アップロード。この一連は Mac 以外では完結しません。当チームは典型的なクロスプラットフォーム分担:Android は Windows/Linux CI、Flutter iOS CI はラックの専用 Mac mini 固定。ネイティブ Xcode 混在なら Xcode ビルドをクラウドへ、Runner 登録と TCO は 自前 macOS Runner を参照。
1)Flutter iOS CI が専用 Mac を要する理由
「一つのコードベース」が解くのはビジネスロジックの再利用であり、ビルド面の再利用ではありません。iOS 成果物は依然としてフル Xcode パイプラインを通り、ubuntu-latest では Flutter iOS CI は成立しません。GitHub ホステッド macOS は分単価が高くキューも不安定で、job ごとにキャッシュが消えると flutter build ipa は再び 15–25 分帯に戻ります。Flutter iOS CI/CD を永続環境の Mac mini に置く価値は、Flutter/Xcode 版の固定、3 層キャッシュの再利用、24/7 スリープなし——Android と iOS のリリース cadence を本当に切り離せます。
flutter test、build apk は Linux に残す。Flutter iOS CI 専用機は iOS 統合ビルドと署名関連のみ。2)Flutter iOS CI クラウド構成図
以下は本番で運用中の Flutter iOS CI/CD トポロジ。開発者全員が手元に Mac を持つ必要はなく、iOS パッケージは self-hosted Runner が生成します。
Flutter iOS CI クラウド構成
ローカル:Dart · Android · git push
ubuntu-latestflutter test · build apk
labels: macos, flutter-ios
fvm flutter build ipapod install · xcodebuild archive
Mac mini 上の永続キャッシュ層(Flutter iOS CI 高速化の要)
~/.pub-cache- CocoaPods cache
- DerivedData
3)Flutter iOS CI の 3 つの運用パターン
| パターン | ローカル/他 CI | クラウド M4 Mac | 向き |
|---|---|---|---|
| A. iOS ビルドだけクラウド | 日常 flutter run、Android パッケージ | build ipa、ストア提出 | ハイブリッド主力(Win/Linux + 実機) |
| B. Flutter フルリモート(稀) | エディタ + git のみ | シミュレータ、flutter doctor 全緑 | 手元 Mac なし、VNC 遅延許容 |
| C. クラウド Mac = iOS Runner | PR で Linux job | ラベル macos の self-hosted Runner | 頻繁リリース、強キャッシュ |
当方は A + C:マージ後 Linux で flutter test;Flutter iOS CI は tag/main マージ時のみ Mac mini Runner。B は短期の Mac なし接続向け、長期は Runner 化推奨。
4)Flutter iOS CI 環境チェックリスト(Mac mini 初回セットアップ)
- Xcode + CLT:
ios/Podfileと Flutter チャネルが要求する最低版に合わせる。インストール後sudo xcodebuild -license accept。 - Flutter SDK:
fvmまたは~/flutter固定。リポに.fvmrcを書き、メンバーと CI の版ズレを防ぐ。 - CocoaPods:
gem install cocoapodsまたは Homebrew。大規模リポはPodfile.lockをコミット。 - 署名: Fastlane Match または Xcode 自動署名。p12 とプロビジョニングはGit に入れない。暗号化リポまたは CI Secret へ。
- ネットワーク: Git リモートと pub.dev/CDN に近いリージョン。社内 Git は VPN/専線。出口要件は ヘルプセンター。
新マシンで初回 flutter doctor -v を実行し、出力を Wiki に貼る——以降のトラブルシュートはこの「ゴールデンスナップショット」から。
5)CocoaPods キャッシュ最適化:Flutter iOS CI 高速化の核(Before/After 付き)
中規模 Flutter リポ(plugins 40+、Release IPA)を 3 環境で各 3 回、中央値で比較——Flutter iOS CI の差はほぼ「キャッシュが Mac mini に残るか」だけです。
| 環境 | 初回ビルド(コールド) | 2 回目(キャッシュヒット) |
|---|---|---|
| 手元 MacBook Air M2(8GB、蓋閉じ/降クロック) | 18–25 min | 12–15 min |
GitHub ホステッド macos-latest(カスタムキャッシュなし) | 16–22 min | 14–18 min |
| Mac mini M4(16GB)· Flutter iOS CI + 3 層キャッシュ | 15–20 min | 4–8 min |
2 回目を 12 分以上から一桁分へ圧縮できるのは構成図の 3 層永続化のおかげ——Flutter iOS build on Mac mini を「ビルドできる」から「CI として使える」へ引き上げた分岐点です。
PUB_CACHE/~/.pub-cache: Runner 環境変数でパス固定、job 間で Dart 依存を再利用。- CocoaPods cache +
ios/Pods:Podfile.lock不変ならpod installスキップ。変更時は増分のみ。 - DerivedData:
~/DerivedData固定。Xcode メジャーアップ以外はcleanしない。
6)Flutter iOS CI コマンドフロー(SSH または Runner スクリプト)
リポルートで実行。Flutter 版はプロジェクト固定版に置き換えてください:
cd ~/work/my_flutter_app
export PUB_CACHE=$HOME/.pub-cache
fvm flutter pub get
cd ios && pod install --repo-update && cd ..
fvm flutter build ipa --release \
--export-options-plist=ios/ExportOptions.plist
GitHub Actions では上記を release-ios.yml に記述し、runs-on: [self-hosted, macos, flutter-ios]。TestFlight アップロード時、Mac mini の出口帯域と App Store Connect 経路は、自宅 Wi‑Fi より安定しがちです。
7)GitHub Actions:Flutter iOS CI/CD workflow の分割
2 workflow に分ける(または matrix の if で分流)ことを推奨:
test-android.yml:ubuntu-latestでflutter test、build apk。release-ios.yml:runs-on: [self-hosted, macos, flutter]。tag またはmainマージ時のみbuild ipa+ アップロード。
クラウド Mac で VNC デバッグと Runner を併用する場合、ビルド用の別システムユーザーを切る——手動編集と自動 checkout の衝突を防ぐ。並列とディスクは Runner TCO を参照。Windows 主力の全体像は Windows + クラウド Mac——Flutter でもローカルに Xcode がない点は同じです。
8)よくある問題:Flutter iOS CI が止まる理由(how/fix)
Google で多い why/how/fix/error 検索に対応——チーム Wiki の入口でもあります。
pod install が 10 分以上かかるのは正常?
Why: Runner が毎回一時ディレクトリに checkout し、CocoaPods ダウンロードキャッシュがマウントされていない。または pod install --repo-update がデフォルトスクリプトに入っている。
Fix: WORK パスを固定。Podfile.lock の hash を比較し、不変ならスキップ。--repo-update は週次メンテ job に移す。
xcodebuild archive 失敗/exit code 65
Why: Flutter と Xcode の版不一致、DerivedData 破損、native plugin が現 SDK 非対応。
Fix: CI 冒頭で fvm flutter doctor -v をログ保存。DerivedData 削除後再実行。Xcode Release Notes でチャネル確認。
signing failed/プロビジョニング不一致
Why: キーチェーンに p12 未インポート、bundle id とプロファイル不一致、Match リポ権限期限切れ。
Fix: Mac mini Runner 専用キーチェーン。Fastlane Match 更新。必要なら VNC で「常に信頼」——Flutter iOS CI で最頻の「コード以外」失敗。
DerivedData 肥大でディスク満杯
Why: 複数ブランチの並列 job、古い Archives 未削除、複数 Flutter 版共存。
Fix: cron で ~/Library/Developer/Xcode/Archives 清理。Runner 並列 1–2。ディスク ≥512GB または定期拡張。
Flutter 版不一致による plugin コンパイルエラー
Why: 開発者が fvm 未使用、CI が別チャネル。
Fix: .fvmrc をコミット。CI は fvm install && fvm flutter pub get 統一。PR テンプレに「Flutter SDK 変更」チェックを追加。
9)専用 Mac mini で Flutter iOS CI を始めるタイミング
| 状況 | 同僚 Mac 借用/中古購入 | クラウド M4 Mac mini |
|---|---|---|
| 月 4 回以上 iOS リリース | 調整コスト大 | 推奨 固定ビルド機 + キャッシュ |
| チームに Mac なし、Flutter のみ | 継続困難 | 日額で試行 本番 build ipa |
| オフィスに Mac mini を 24/7 設置済み | 自前で十分 | クラウド Mac は DR またはピーク |
| 多数の iOS plugin でネイティブ調整 | 手元 Mac が便利 | クラウドで release、手元で debug |
10)FAQ(Flutter iOS CI/CD)
Flutter iOS CI とネイティブ iOS CI の違いは?flutter pub get と plugin コード生成が 1 層増え、版は .fvmrc と一致必須。Xcode 側は Pods + archive のまま。
Codemagic/ホステッド macOS との比較は?
ホステッドは検証向き。2 回目ビルドを 10 分以内 に安定させ、強キャッシュが必要なら Flutter iOS build on Mac mini + self-hosted Runner の方が制御しやすい。
初回 Flutter iOS CI 通過までの目安は?
慣れていれば約 1 営業日:Xcode/Flutter 導入、Runner 登録、署名設定、build ipa → TestFlight まで 1 本。
エンジニアリング結論:Flutter iOS CI 最小構成(MVF)
Flutter プロジェクトで週 1 回以上 iOS を出す、かつ Windows/Linux 主力がいるなら、現実的な最小構成は次のとおりです:
- 16GB Mac mini M4 を 1 台(物理または専用クラウド)で Flutter iOS CI 専任;
- self-hosted macOS Runner を登録し、Linux 側
flutter test/build apkと workflow 分離; .pub-cache、CocoaPods cache、DerivedData の 3 層を永続化;- 目標:48 時間以内に本番リポで最初の
flutter build ipa→ TestFlight。その後、並列・DR 用 2 台目を検討。
当方は同じ MVF で 2 回目ビルドを 4–8 分 帯に圧縮(第 5 節の表参照)。専用 Mac mini ノードと SSH 納品は 料金 と ヘルプセンター でリリース頻度に照らして試算——まず pipeline を検証し、拡張はその後。