Offre

Pourquoi Flutter iOS CI ralentit sur un Mac cloud ? L'invalidation de cache en trois couches

CI Flutter · build iOS
2026-06-04 ~15 min

Une idée : Flutter iOS CI est une propagation d'invalidation de cache. Priorité CocoaPods, puis DerivedData. Après §0 et §0.1, vous savez quoi corriger en premier sur Mac cloud loué ou runner GitHub Actions macOS.

30 secondes (priorités)

  1. Goulot principal : Pods (réseau + résolution) > DerivedData > cache Flutter — Pods d'abord.
  2. Cause unique : pas « trois couches lentes », mais miss amont force la réécriture aval (§1).
  3. Une règle (§0) : cache lié aux lockfiles/SDK, pas à la date.
  4. Pressé : §0+§0.1+§4 CocoaPods ; build chaud lent → §5.
  5. §7 : l'ordre restore prime sur les clés.
Flutter iOS CI et cache sur Mac cloud
Illustration ; conditions benchmark ci-dessous.

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.lock changement → 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èlesPods 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_PATH CI dédié.
  • Planification : xcodebuild + indexation agent → swap ; 16 Go : agents jour, CI nuit.
  • Pas de croisement : pas de pod update sur ios/Pods CI.

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)
1pub 🔥PUB_CACHEpubspec.lock + Flutter SDK
2–3pods 🔥🔥🔥~/.cocoapods + ios/PodsPodfile.lock + CP version
4deriveddata 🔥🔥$DERIVED_DATA_PATHXcode + 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