Cet article ne traite que d’un sujet : Flutter iOS CI/CD (ancre SEO : Flutter iOS build on Mac mini) — comment exécuter flutter build ipa de façon stable sur un Mac mini M4, en séparant le cache CocoaPods, un self-hosted macOS Runner et les jobs Android/tests sous Linux. Le vrai goulot d’étranglement Flutter n’est rarement Dart : c’est la dépendance Mac de la chaîne iOS : pod install → xcodebuild archive → signature → envoi TestFlight. Cette chaîne ne se termine que sur Mac. Notre équipe fait la répartition classique : Android sur CI Windows/Linux, Flutter iOS CI fixé sur un Mac mini dédié en rack. Mélange Xcode natif ? Voir builds Xcode lents vers le cloud ; inscription Runner et TCO : runners macOS self-hosted.
1) Pourquoi Flutter iOS CI exige un Mac dédié
« Une seule base de code » réutilise la logique métier, pas le plan de build. Les artefacts iOS passent toujours par Xcode ; impossible de faire du Flutter iOS CI sur ubuntu-latest. Le macOS hébergé par GitHub coûte cher à la minute, la file d’attente fluctue, et sans cache persistant flutter build ipa retombe vers 15–25 minutes. Placer Flutter iOS CI/CD sur un Mac mini persistant apporte : versions Flutter/Xcode verrouillées, cache à trois niveaux réutilisable, 24/7 sans veille au rabais — les rythmes de release Android et iOS se découplent vraiment.
flutter test, build apk restent sur Linux. La machine Flutter iOS CI ne fait que build iOS intégré et signature.2) Schéma cloud Flutter iOS CI
Voici la topologie Flutter iOS CI/CD que nous utilisons en prod : pas besoin que chaque développeur ait un Mac local ; le paquet iOS sort du self-hosted Runner.
Architecture cloud Flutter iOS CI
local : Dart · Android · git push
ubuntu-latestflutter test · build apk
labels: macos, flutter-ios
fvm flutter build ipapod install · xcodebuild archive
Couches de cache persistantes sur le Mac mini (clé d’accélération Flutter iOS CI)
~/.pub-cache- CocoaPods cache
- DerivedData
3) Trois modes de déploiement Flutter iOS CI
| Mode | Local / autre CI | Mac M4 cloud | Adapté à |
|---|---|---|---|
| A. Build iOS seulement dans le cloud | flutter run, paquets Android | build ipa, envoi store | Hybride (Win/Linux + appareil) |
| B. Flutter 100 % distant (rare) | éditeur + git | simulateur, flutter doctor OK | pas de Mac local, latence VNC OK |
| C. Mac cloud = Runner iOS | PR déclenche job Linux | self-hosted Runner label macos | releases fréquentes, cache fort |
Nous faisons A + C : après merge, flutter test sur Linux ; Flutter iOS CI uniquement sur tag / merge main via le Runner Mac mini. B convient à court terme sans Mac ; à long terme, industrialiser le Runner.
4) Checklist environnement Flutter iOS CI (installation unique sur Mac mini)
- Xcode + CLT : alignés sur
ios/Podfileet le minimum du canal Flutter. Puissudo xcodebuild -license accept. - Flutter SDK :
fvmou~/flutterfixe ;.fvmrcdans le dépôt pour aligner équipe et CI. - CocoaPods :
gem install cocoapodsou Homebrew ; gros dépôts : committerPodfile.lock. - Signature : Fastlane Match ou signature auto Xcode. p12 et profils pas dans Git — dépôt chiffré ou secrets CI.
- Réseau : région proche du remote Git et pub.dev/CDN ; Git d’entreprise via VPN/ligne — sortie décrite dans le centre d’aide.
Au premier flutter doctor -v sur la nouvelle machine, coller la sortie au wiki — c’est la « snapshot dorée » pour le dépannage.
5) Optimisation cache CocoaPods : cœur de l’accélération Flutter iOS CI (Before/After)
Même dépôt Flutter moyen (~40+ plugins, IPA Release), 3 exécutions par environnement, médiane — l’écart en Flutter iOS CI tient presque entièrement au cache restant sur le Mac mini.
| Environnement | Premier build (froid) | Deuxième build (cache) |
|---|---|---|
| MacBook Air M2 local (8 Go, capot/ throttle) | 18–25 min | 12–15 min |
GitHub macos-latest (sans cache custom) | 16–22 min | 14–18 min |
| Mac mini M4 (16 Go) · Flutter iOS CI + 3 caches | 15–20 min | 4–8 min |
Passer le second build de 12+ minutes à un chiffre unique : les trois couches persistantes du schéma — le seuil où Flutter iOS build on Mac mini passe de « ça compile » à « ça tient en CI ».
PUB_CACHE/~/.pub-cache: variable Runner fixe, réutilisation des deps Dart entre jobs.- Cache CocoaPods +
ios/Pods:Podfile.lockinchangé → sauterpod install; sinon incrémental. - DerivedData :
~/DerivedDatafixe ; pas decleansauf upgrade majeur Xcode.
6) Flux de commandes Flutter iOS CI (SSH ou script Runner)
À la racine du dépôt ; remplacez la version Flutter par celle du projet :
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
Dans GitHub Actions, mettre ces étapes dans release-ios.yml, runs-on: [self-hosted, macos, flutter-ios]. À l’upload TestFlight, la bande passante sortante du Mac mini et la route App Store Connect sont souvent plus stables que le Wi‑Fi maison.
7) GitHub Actions : scinder les workflows Flutter iOS CI/CD
Deux workflows (ou matrix avec if) :
test-android.yml:ubuntu-latest,flutter test,build apk.release-ios.yml:runs-on: [self-hosted, macos, flutter],build ipa+ upload seulement sur tag ou mergemain.
Si VNC debug et Runner tournent ensemble sur le Mac cloud, utilisateur système séparé pour les builds — éviter le conflit édition manuelle / checkout auto. Parallélisme et disque : TCO Runner. Poste Windows principal : Xcode sous Windows + Mac cloud — même logique Flutter, sans Xcode local.
8) Problèmes fréquents : pourquoi Flutter iOS CI bloque (how/fix)
Aligné sur les recherches why/how/fix/error — entrée wiki de l’équipe.
pod install >10 minutes, c’est normal ?
Why : checkout à chaque fois dans un dossier temporaire, cache téléchargement CocoaPods non monté, ou pod install --repo-update dans le script par défaut.
Fix : chemin WORK fixe ; comparer le hash de Podfile.lock, sauter si identique ; --repo-update dans un job de maintenance hebdo.
échec xcodebuild archive / exit code 65
Why : versions Flutter/Xcode incohérentes, DerivedData corrompu, plugin natif incompatible SDK.
Fix : fvm flutter doctor -v en tête de CI avec logs ; supprimer DerivedData et relancer ; Xcode Release Notes pour le canal.
signing failed / profil incompatible
Why : p12 absent du trousseau, bundle id ≠ profil, dépôt Match expiré.
Fix : trousseau dédié sur le Runner Mac mini ; renouveler Fastlane Match ; VNC « toujours faire confiance » si besoin — échec « hors code » le plus fréquent en Flutter iOS CI.
DerivedData remplit le disque
Why : jobs parallèles multi-branches, vieilles Archives, plusieurs versions Flutter.
Fix : cron sur ~/Library/Developer/Xcode/Archives ; parallélisme Runner 1–2 ; disque ≥512 Go ou extension régulière.
versions Flutter divergentes → erreur compilation plugin
Why : dev sans fvm, CI sur autre canal.
Fix : committer .fvmrc ; CI unifié fvm install && fvm flutter pub get ; case « SDK Flutter modifié ? » dans le template PR.
9) Quand prendre un Mac mini dédié pour Flutter iOS CI
| Votre cas | Emprunter un Mac / acheter d’occasion | Mac mini M4 cloud |
|---|---|---|
| ≥4 releases iOS/mois | coût de coordination | recommandé build fixe + cache |
| équipe sans Mac, Flutter seul | peu durable | location journalière pour un vrai build ipa |
| Mac mini 24/7 au bureau | self-host suffit | Mac cloud en DR ou pic |
| beaucoup de plugins iOS natifs | Mac local pratique | release cloud, debug local |
10) FAQ (Flutter iOS CI/CD)
Différence Flutter iOS CI vs CI iOS natif ?
Couche flutter pub get + codegen plugins ; version = .fvmrc ; côté Xcode : Pods + archive.
vs Codemagic / macOS hébergé ?
Hébergé pour valider vite ; pour un 2e build stable sous 10 min avec cache fort, Flutter iOS build on Mac mini + self-hosted Runner est plus maîtrisable.
Délai pour le premier passage ?
~1 jour ouvré si habitué : Xcode/Flutter, Runner, signature, un build ipa → TestFlight.
Conclusion technique : solution minimale Flutter iOS CI (MVF)
Si votre projet Flutter publie iOS au moins une fois par semaine et que l’équipe vit sur Windows/Linux, le minimum viable :
- 1 Mac mini M4 16 Go (physique ou cloud exclusif) dédié Flutter iOS CI ;
- self-hosted macOS Runner, workflows séparés pour
flutter test/build apksous Linux ; - cache persistant :
.pub-cache, CocoaPods, DerivedData ; - objectif : premier
flutter build ipa→ TestFlight avec le vrai dépôt en 48 h, puis éventuellement une 2e machine pour parallèle/DR.
Nous tenons les builds suivants à 4–8 minutes avec ce MVF (tableau §5). Nœud Mac mini exclusif et SSH : tarifs et centre d’aide selon votre cadence — valider la pipeline avant de scaler.