30 секунд (приоритет)
- Главный конфликт: Pods (сеть + resolve) > DerivedData > Flutter cache — сначала Pods.
- Одна причина: не «три слоя медленны», а промах вверх по цепочке заставляет переделывать вниз (§1).
- Одно правило (§0): кэш привязан к lockfile/SDK, не к дате.
- Мало времени: §0+§0.1+§4 CocoaPods; hot медленный → §5.
- §7: порядок restore важнее строк key.
0. Единственный принцип кэша
До CocoaPods, DerivedData, PUB_CACHE:
CI-кэш связывает детерминизм сборки, а не «хранит файлы».
pubspec.lock/Podfile.lockизменение → miss → норма- апгрейд Xcode/Flutter → miss → норма
- время Job, дата, суффикс → не должны сами вызывать miss
Симптом: каждый день cold start — кэш по дате или полный wipe.
0.1 Реальный порядок узких мест
Все разделы — одно суждение: слои не равны:
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
Итог: медленность редко три параллельные проблемы — Pods сначала держат потолок; без hit Pods DerivedData крутится вхолостую.
Маршрут: 10 мин → §0+§0.1+§4; cold ~15, hot медленный → §5; §6 для образа и первого pub.
1. Одна причина: распространение до IPA
Не три подсистемы — одна цепочка.
Зависло на Running pod install... — §0.1: кэш Pods / сеть. Сегменты: pub → pod → xcodebuild.
1.1 Цепочка
Читать по причинности:
[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)
Обратно: pubspec.lock → плагины → pod → DerivedData. Restore: Pub первым; бюджет: Pods → DerivedData → Flutter.
Цитата: ~90 % «Flutter CI медленный» — сбой вверх по цепочке.
Документация: Flutter iOS deployment · CocoaPods environment · Xcode Build Settings.
2. Benchmark: веса §0.1
Таблица доказывает Pods, потом DerivedData. Типичный кейс kvmboot (средний Flutter, ~40 Pod, Release, облачный Mac M4); тот же commit.
| Этап | Вес | cold | hot | Заметки |
|---|---|---|---|---|
| Без кэша | — | ~28 min | ~28 min | Цепь разорвана |
| Только Pods+Specs | 🔥🔥🔥 | ~19 min | ~12 min | Макс. шаг; сначала |
| + DerivedData | 🔥🔥 | ~11 min | ~6 min | Hot build |
| + Flutter pub | 🔥 | ~10 min | ~5 min | Край |
cold >20 → §4. cold ~11, hot >12 → §5.
Самотест: Четыре строки wall; фиксируйте commit и FLUTTER_VERSION.
3. Два агента на одном хосте
Статья-компаньон 2026-06-03: Два AI-агента на облачном Mac: изоляция Claude Code + Codex (2026-06-03) — два CLI не ломают worktree. Ночной Flutter iOS CI на той же аренде Mac:
- Разные корни кэша: CI
DERIVED_DATA_PATH. - Разное расписание: xcodebuild + индексация → swap; 16 ГБ: агенты днём, CI ночью.
- Без пересечений: не
pod updateв CIios/Pods.
4. CocoaPods CI 🔥🔥🔥
Основной слой. ~70 % Flutter iOS build slow в pod install. §0: Podfile.lock.
4.1 Окружение
export CP_HOME_DIR="${CP_HOME_DIR:-$HOME/.cocoapods}"
export COCOAPODS_PARALLEL_CODE_DOWNLOAD=true
# persist: ~/.cocoapods/repos + ~/Library/Caches/CocoaPods
Приватные specs: GitHub Actions macOS runner / облачный Mac в регионе Git. Bitrise vs self-hosted Mac.
4.2 Дерево Pods/
- Обычно: кэш
ios/Pods. - Compliance: коммит
Pods/,--deployment.
Без слепого pod update.
Явный pod install --verbose перед flutter build ipa.
5. DerivedData 🔥🔥
Hot ~6 мин после 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
Tier-очистка; диск: управление диском/inode runner.
6. Кэш Flutter 🔥
Первые загрузки.
Не restore build/ios между job; Docker-разделение.
7. Pipeline GitHub Actions
YAML §4–§6.
| № | Блок | Пути | Ключи (§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') }}
Подпись: codesign / Notarization.
Ловушки: pod до restore; нет save при fail — if: always().
8. Диск и inode
Три слоя → 60 % на 256 ГБ; inode раньше места. матрица релизного спринта.
du -sh ~/Library/Developer/Xcode/DerivedData ~/.cocoapods "${PUB_CACHE:-$HOME/.pub-cache}" 2>/dev/null
df -h .; df -i .
9. Приёмка
① pod <90s ② hot −40 % ③ pub опционален.
| Симптом | Причина | Действие |
|---|---|---|
| hot≈cold 20+ | DerivedData каждый job | путь/restore |
| только pod | CDN/авторизация | CP_HOME_DIR |
| ошибки link | смешение Xcode | ключ+Xcode |
| SSH тормозит | диск/inode | df |
10. FAQ
10.1 Почему так медленно?
Промах CocoaPods. Сначала Pods.
10.2 Pods или DerivedData?
Pods.
10.3 Только DerivedData?
Нет.
10.4 Кэш на runner?
§7; if: always().
10.5 Два агента?
2026-06-03: worktree; здесь корни CI.
11. Итог
CocoaPods (🔥🔥🔥) → DerivedData (🔥🔥) → Flutter (🔥).
Проверка за 48 ч
После Два AI-агента на облачном Mac: изоляция Claude Code + Codex (2026-06-03) — ночной pipeline на том же Mac.
Онбординг: чеклист аренды Mac · спецификации · тарифы