30 secondes (priorités)
- Goulot principal : Pods (réseau + résolution) > DerivedData > cache Flutter — Pods d'abord.
- Cause unique : pas « trois couches lentes », mais miss amont force la réécriture aval (§1).
- Une règle (§0) : cache lié aux lockfiles/SDK, pas à la date.
- Pressé : §0+§0.1+§4 CocoaPods ; build chaud lent → §5.
- §7 : l'ordre restore prime sur les clés.
0. Le seul principe de cache
Avant CocoaPods, DerivedData, PUB_CACHE :
Le cache CI lie le déterminisme de build — pas « stocker des fichiers ».
pubspec.lock/Podfile.lockchangement → miss → normal- upgrade Xcode/Flutter → miss → normal
- horodatage Job, date, suffixe → non seuls
Symptôme : chaque jour = cold start — gestion par date ou wipe total.
0.1 Ordre réel des goulots
Tout le article suit un jugement — couches inégales :
Time ceiling (optimize in this order):
CocoaPods (network + resolve) 🔥🔥🔥 often ~70% of ceiling
↓
DerivedData (compile increment) 🔥🔥 hot builds → ~6 min tier
↓
Flutter cache (toolchain) 🔥 mainly first-run pub / engine
Verdict : la lenteur n'est pas trois problèmes parallèles — Pods plafonnent d'abord ; sans hit Pods, DerivedData tourne à vide en aval.
Parcours : 10 min → §0+§0.1+§4 ; cold ~15 min, hot lent → §5 ; §6 pour image et premier pub.
1. Cause unique : propagation jusqu'à l'IPA
Pas trois sous-systèmes — une chaîne. Rupture amont ou aval ?
Si flutter build ipa bloque sur Running pod install..., §0.1 : cache Pods / réseau avant les flags Xcode. Mesures : pub → pod → xcodebuild.
1.1 Chaîne
Lire en sens causal :
[start · primary] CocoaPods miss / slow private specs
│ Pod tree rebuild, Specs fetch
▼
[propagate] DerivedData forced cold (full xcodebuild)
│
▼
[end] Slow IPA (often blamed on Flutter/Dart)
Sens inverse aussi : pubspec.lock → plugins → pod → DerivedData invalidé. Restore : Pub d'abord ; budget debug : Pods → DerivedData → Flutter.
Citation : ~90 % « Flutter CI lent » = chaîne amont, pas le compilateur.
Références: Flutter iOS deployment · CocoaPods environment · Xcode Build Settings.
2. Benchmark : poids §0.1
Le tableau prouve Pods d'abord, DerivedData ensuite. Cas kvmboot typique (Flutter moyen, ~40 Pods, Release, Mac cloud M4) ; même commit.
| Étape | Poids | cold | hot | Notes |
|---|---|---|---|---|
| Sans cache | — | ~28 min | ~28 min | Chaîne rompue |
| Pods+Specs seuls | 🔥🔥🔥 | ~19 min | ~12 min | Plus grosse baisse ; en premier |
| + DerivedData | 🔥🔥 | ~11 min | ~6 min | Build chaud |
| + pub Flutter | 🔥 | ~10 min | ~5 min | Marginal |
Cold >20 min → §4. Cold ~11, hot >12 → §5.
Auto-mesure : Quatre lignes wall ; commit et FLUTTER_VERSION fixes.
3. Dual-agent sur même hôte : limites
Article compagnon du 2026-06-03 : Mac cloud double agent IA : isolation Claude Code + Codex (2026-06-03) — deux CLI, un worktree intact. CI Flutter iOS de nuit sur le même Mac cloud loué :
- Racines cache séparées :
DERIVED_DATA_PATHCI dédié. - Planification : xcodebuild + indexation agent → swap ; 16 Go : agents jour, CI nuit.
- Pas de croisement : pas de
pod updatesurios/PodsCI.
4. Optimisation CocoaPods CI 🔥🔥🔥
Couche primaire. ~70 % du Flutter iOS build slow dans pod install. §0 : Podfile.lock.
4.1 Variables d'environnement
export CP_HOME_DIR="${CP_HOME_DIR:-$HOME/.cocoapods}"
export COCOAPODS_PARALLEL_CODE_DOWNLOAD=true
# persist: ~/.cocoapods/repos + ~/Library/Caches/CocoaPods
Specs privées : runner GitHub Actions macOS ou Mac cloud même région que Git. Bitrise vs runners Mac auto-hébergés.
4.2 Arbre Pods/
- Courant : cache
ios/Pods. - Conformité : commit
Pods/,--deployment.
Pas de pod update aveugle.
pod install --verbose puis flutter build ipa.
5. DerivedData 🔥🔥
Hot ~6 min après hit Pods.
export DERIVED_DATA_PATH="/var/ci/derived/flutter-${FLUTTER_VERSION}-xcode-${XCODE_VERSION}"
xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner \
-configuration Release -derivedDataPath "$DERIVED_DATA_PATH" \
-destination 'generic/platform=iOS' build
Nettoyage par paliers ; disque : gouvernance disque/inode runner.
6. Cache toolchain Flutter 🔥
Téléchargements premier run.
Ne pas restaurer build/ios entre jobs ; guide Docker.
7. Pipeline GitHub Actions
YAML §4–§6.
| Ordre | Bloc | Chemins | Clés (§0) |
|---|---|---|---|
| 1 | pub 🔥 | PUB_CACHE | pubspec.lock + Flutter SDK |
| 2–3 | pods 🔥🔥🔥 | ~/.cocoapods + ios/Pods | Podfile.lock + CP version |
| 4 | deriveddata 🔥🔥 | $DERIVED_DATA_PATH | Xcode + Flutter + lockfiles |
# .github/workflows/flutter-ios.yml (structure; macos-latest or self-hosted cloud Mac)
jobs:
build-ios:
runs-on: macos-14 # or runs-on: [self-hosted, cloud-mac]
steps:
- uses: actions/checkout@v4
# ── Restore (order: Pub → Pods Specs → Pods tree → DerivedData) ──
- name: Restore Pub Cache
uses: actions/cache/restore@v4
with:
path: ${{ env.PUB_CACHE }}
key: pub-${{ hashFiles('pubspec.lock') }}-flutter-${{ env.FLUTTER_VERSION }}
- name: Restore CocoaPods Specs
uses: actions/cache/restore@v4
with:
path: |
~/.cocoapods
~/Library/Caches/CocoaPods
key: pods-specs-${{ env.COCOAPODS_VERSION }}
- name: Restore Pods Tree
uses: actions/cache/restore@v4
with:
path: ios/Pods
key: pods-tree-${{ hashFiles('ios/Podfile.lock') }}
- name: Restore DerivedData
uses: actions/cache/restore@v4
with:
path: ${{ env.DERIVED_DATA_PATH }}
key: dd-${{ env.XCODE_VERSION }}-${{ env.FLUTTER_VERSION }}-${{ hashFiles('pubspec.lock', 'ios/Podfile.lock') }}
# ── Build ──
- name: Flutter Pub Get
run: flutter pub get
- name: Pod Install
run: cd ios && pod install --verbose
- name: Flutter Build IPA
run: flutter build ipa --release --export-options-plist=ios/ExportOptions.plist
# ── Save (mirror restore; save costly layers even on failure) ──
- name: Save Pub Cache
uses: actions/cache/save@v4
if: always()
with:
path: ${{ env.PUB_CACHE }}
key: pub-${{ hashFiles('pubspec.lock') }}-flutter-${{ env.FLUTTER_VERSION }}
- name: Save Pods + DerivedData
uses: actions/cache/save@v4
if: always()
with:
path: |
~/.cocoapods
~/Library/Caches/CocoaPods
ios/Pods
${{ env.DERIVED_DATA_PATH }}
key: dd-${{ env.XCODE_VERSION }}-${{ env.FLUTTER_VERSION }}-${{ hashFiles('pubspec.lock', 'ios/Podfile.lock') }}
Signature : codesign / Notarization.
Pièges : pod avant restore ; pas de save si échec — if: always().
8. Disque et inode
Trois caches → 60 % sur 256 Go ; inode souvent avant la capacité. matrice build sprint.
du -sh ~/Library/Developer/Xcode/DerivedData ~/.cocoapods "${PUB_CACHE:-$HOME/.pub-cache}" 2>/dev/null
df -h .; df -i .
9. Acceptation
① pod <90s ② hot −40 % ③ pub optionnel.
| Symptôme | Cause | Action |
|---|---|---|
| hot≈cold 20+ | DerivedData effacé | chemin/restore |
| pod seul | CDN/auth | CP_HOME_DIR |
| erreurs link | mélange Xcode | clé+Xcode |
| SSH lent | disque/inode | df |
10. FAQ
10.1 Pourquoi si lent sur Mac cloud ?
Miss CocoaPods → chaîne. Pods d'abord.
10.2 Pods ou DerivedData ?
Pods d'abord.
10.3 DerivedData seul ?
Non.
10.4 Cache runner ?
§7 ; if: always().
10.5 Dual-agent ?
2026-06-03 worktree ; ici racines CI.
11. Conclusion
CocoaPods (🔥🔥🔥) → DerivedData (🔥🔥) → Flutter (🔥).
Valider en 48 h
Après Mac cloud double agent IA : isolation Claude Code + Codex (2026-06-03) pipeline de nuit sur le même Mac loué.
Onboarding : checklist louer un Mac · offres · forfaits