Déployer automatiquement une app Flutter
Ce cookbook couvre la mise en place complète des pipelines CI/CD pour une application Flutter. Pour le contexte global (architecture, diagrammes, FAQ), voir la page principale.
Objectif : configurer des pipelines Bitbucket manuels pour déployer une app Flutter sur Google Play Store (Android) et TestFlight (iOS via Xcode Cloud), en un seul clic.
Flutter : 4hPré-requis
- Dépôt Bitbucket avec Pipelines activés
- App Flutter configurée avec des flavors (
preprod/prod) viaflutter_flavorizr - Compte Google Play Console avec l'app créée
- Compte Apple Developer Program avec accès à App Store Connect et Xcode Cloud
- Fastlane (installé dans le pipeline via
gem install) - Ruby (présent dans l'image Docker CI)
Image Docker CI
image: ghcr.io/cirruslabs/flutter:3.38.5
Contient Flutter, Dart, Android SDK, Ruby et les outils de base.
Vue d'ensemble technique
| Élément | Rôle |
|---|---|
bitbucket-pipelines.yml | Définition de tous les pipelines CI/CD |
Makefile | Commandes de build et deploy partagées entre local et CI |
scripts/asc.rb | Client API App Store Connect (génère JWT, déclenche Xcode Cloud) |
ios/ci_scripts/ci_post_clone.sh | Installe Flutter et CocoaPods dans Xcode Cloud |
Partie 1 — Configuration initiale des secrets
Avant le premier déploiement, tous les secrets doivent être encodés en base64 et ajoutés dans Bitbucket.
1.1 Android — Compte de service Google Play
Créer le compte de service
- Aller sur Google Cloud Console
- Sélectionner (ou créer) le projet lié à l'app → API et services → Bibliothèque → activer Google Play Android Developer API

- IAM et administration → Comptes de service → Créer un compte de service
- Nom :
release-account(ou similaire) - Rôle : aucun (les permissions sont données côté Play Console)
- Nom :

- Cliquer sur le compte créé → onglet Clés → Ajouter une clé → JSON

- Télécharger le fichier
.json→ le renommergoogle-play-key.json - Placer le fichier dans
private_keys/google-play-key.json(ignoré par git)
Donner accès dans la Play Console
- Aller sur Google Play Console -> Paramètres → Utilisateurs et autorisations
- Onglet Autorisations de l'application → cocher l'app
- Droits nécessaires : Gestionnaire des versions (Release manager)
- Inviter l'utilisateur et confirmer

Encoder les secrets de signature
Répéter l'opération pour chaque environnement :
# ── Preprod ──
echo "=== ANDROID_KEYSTORE_B64_PREPROD ==="
base64 -i android/upload-key-preprod.keystore | tr -d '\n'
echo
echo "=== ANDROID_KEY_PROPERTIES_B64_PREPROD ==="
base64 -i android/key-preprod.properties | tr -d '\n'
echo
echo "=== GOOGLE_PLAY_JSON_KEY_B64_PREPROD ==="
base64 -i private_keys/google-play-key-preprod.json | tr -d '\n'
echo
1.2 iOS — Clé API App Store Connect
Créer la clé API
- Aller sur App Store Connect → Clés d'API
- Générer une clé API
- Nom :
CI Xcode Cloud preprod(ou similaire) - Accès : Admin (nécessaire pour déclencher des builds Xcode Cloud)
- Nom :
- Noter l'Issuer ID (affiché en haut de la page, commun à toutes les clés du compte)
- Noter l'ID de la clé
- Télécharger la clé (
AuthKey_XXXXXXXXXX.p8) — elle ne peut être téléchargée qu'une seule fois

Il est recommandé de créer une clé distincte pour preprod et pour prod. Répéter la démarche ci-dessus pour chaque environnement.
Encoder la clé .p8
# Preprod
echo "=== ASC_PRIVATE_KEY_B64_PREPROD ==="
base64 -i private_keys/AuthKey_<PREPROD_KEY_ID>.p8 | tr -d '\n'
echo
1.3 Ajouter toutes les variables dans Bitbucket
Dépôt → Paramètres → Variables du dépôt :

Android
| Variable | Source | Sécurisée |
|---|---|---|
GOOGLE_PLAY_JSON_KEY_B64_PREPROD | Compte de service Google Cloud preprod (JSON encodé base64) | ✅ |
ANDROID_KEYSTORE_B64_PREPROD | Keystore de signature preprod encodé base64 | ✅ |
ANDROID_KEY_PROPERTIES_B64_PREPROD | Fichier key.properties preprod encodé base64 | ✅ |
iOS
| Variable | Source | Sécurisée |
|---|---|---|
ASC_KEY_ID_PREPROD | ID de la clé API App Store Connect (preprod) | ❌ |
ASC_ISSUER_ID_PREPROD | Issuer UUID App Store Connect (preprod) | ❌ |
ASC_PRIVATE_KEY_B64_PREPROD | Clé .p8 preprod encodée base64 | ✅ |
ASC_WORKFLOW_ID_PREPROD | ID du workflow Xcode Cloud preprod -> ajouté + tard | ❌ |
Variables optionnelles
| Variable | Usage |
|---|---|
ANDROID_TRACK | Track Play Store : internal (défaut), alpha, beta, production |
Les variables marquées sécurisées ne seront plus visibles après enregistrement dans Bitbucket. Note-les dans un gestionnaire de mots de passe si nécessaire.
Partie 2 — Android : Google Play Store via Fastlane
2.1 Principe
Le pipeline Linux build l'AAB (Android App Bundle) signé puis l'upload directement sur le Play Store via fastlane supply.
2.2 Signature
La signature utilise upload-key.keystore configuré dans android/key.properties :
storePassword=***
keyPassword=***
keyAlias=upload-key
storeFile=upload-key.keystore
Ces fichiers ne sont pas commités (.gitignore). En CI, ils sont recréés depuis les variables base64.
2.3 Flavors et Package IDs
| Flavor | Package ID | Play Store |
|---|---|---|
preprod | fr.doing.starter | Track internal |
prod | fr.doing.starter | Track internal (ou production) |
2.4 Étape pipeline : décodage des secrets
- step: &deploy-android-preprod
name: '🤖 Android preprod → Play Store (internal)'
image: ghcr.io/cirruslabs/flutter:3.38.5
size: 2x # 8 Go RAM (Gradle + Flutter dépassent 4 Go)
caches:
- gradle
- android-sdk
- pub-cache
script:
- gem install fastlane --no-document -q
- mkdir -p private_keys android
- printf '%s' "$GOOGLE_PLAY_JSON_KEY_B64_PREPROD" | base64 -d > private_keys/google-play-key.json
- printf '%s' "$ANDROID_KEYSTORE_B64_PREPROD" | base64 -d > android/upload-key.keystore
- printf '%s' "$ANDROID_KEY_PROPERTIES_B64_PREPROD" | base64 -d > android/key.properties
- make deploy-android-preprod FLUTTER=flutter DART=dart GOOGLE_PLAY_JSON_KEY=$(pwd)/private_keys/google-play-key.json
artifacts:
- build/app/outputs/bundle/preprodRelease/**
Les steps Android doivent utiliser size: 2x (8 Go RAM). Gradle + Flutter dépassent la limite par défaut de 4 Go. Vérifie aussi que android/gradle.properties contient -Xmx ≤ 3g.
2.5 Commande Makefile
deploy-android-preprod: _check-fastlane-supply
# 1. Récupère le dernier build number depuis Play Store et incrémente
@LATEST=$$(fastlane run google_play_track_version_codes \
json_key:"$(GOOGLE_PLAY_JSON_KEY)" \
package_name:"fr.doing.starter" \
track:"$(ANDROID_TRACK)" 2>/dev/null \
| grep -Eo '[0-9]+' | sort -n | tail -1 || echo "0"); \
NEW=$$(($$LATEST + 1)); \
# 2. Build avec le nouveau build number
$(FLUTTER) build appbundle --build-number=$$NEW \
--flavor preprod --dart-define=FLAVOR=preprod \
-t "lib/main.dart" --release; \
# 3. Upload vers Play Store
fastlane supply \
--aab build/app/outputs/bundle/preprodRelease/app-preprod-release.aab \
--json_key "$(GOOGLE_PLAY_JSON_KEY)" \
--package_name fr.doing.starter \
--track $(ANDROID_TRACK) \
--release_status $(ANDROID_RELEASE_STATUS) \
--skip_upload_apk true \
--skip_upload_metadata true \
--skip_upload_images true \
--skip_upload_screenshots true
_check-fastlane-supply:
@command -v fastlane >/dev/null 2>&1 \
|| (echo "$(RED)fastlane introuvable. Installer avec : gem install fastlane$(NC)" && exit 1)
@[ -f "$(GOOGLE_PLAY_JSON_KEY)" ] \
|| (echo "$(RED)Clé introuvable : $(GOOGLE_PLAY_JSON_KEY)\nPoser google-play-key.json à la racine ou définir GOOGLE_PLAY_JSON_KEY=chemin/vers/key.json$(NC)" && exit 1)
2.6 Build number automatique
Le build number n'est pas géré manuellement. Le Makefile interroge Fastlane pour récupérer le dernier build number présent sur le Play Store et l'incrémente automatiquement à chaque déploiement :
Dernier build number Play Store → +1 → build Flutter → upload
Il n'est donc pas nécessaire de modifier pubspec.yaml avant chaque déploiement Android.
2.7 Premier déploiement Android
Pour la première publication sur le Play Store :
- Compléter la fiche de l'app dans la Play Console (screenshots, description, etc.)
- Lancer le pipeline avec
ANDROID_RELEASE_STATUS=draftpour le premier upload - Une fois la fiche validée, les uploads suivants utilisent
completed(valeur par défaut)
Partie 3 — iOS : TestFlight via Xcode Cloud
3.1 Pourquoi Xcode Cloud ?
Bitbucket Pipelines n'offre pas de runners macOS. Or, un Mac est indispensable pour builder une app iOS (Xcode, codesigning, etc.). Xcode Cloud est inclus gratuitement avec l'Apple Developer Program (25h/mois).
Le pipeline Bitbucket ne build rien pour iOS — il se contente de déclencher un build Xcode Cloud via l'API App Store Connect.
3.2 Configurer le workflow Xcode Cloud
Connecter le dépôt Bitbucket
- Ouvrir le projet dans Xcode → Integrate → Xcode Cloud → Create Workflow (ou via le menu Source Control)
Attention, bien créer le workflow depuis Runner.xcworkspace (et non Runner.xcodeproj) pour que les pods soient inclus dans le graphe de dépendances. Changer cela sur appstoreconnect dans "Projet ou espace de travail" si nécessaire. 2. Xcode demande de connecter un SCM → choisir Bitbucket 3. S'authentifier et autoriser l'accès au dépôt
Créer le workflow
Dans la configuration du workflow, sur "edit workflow", utiliser les paramètres suivants (il est parfois nécessaire de supprimer la valeur par défaut, puis d'appuyer sur +) :
| Paramètre | Valeur |
|---|---|
| Nom | preprod archive (ou prod archive) |
| Scheme | preprod (ou prod) |
| Actions | Archive → iOS / App store |
| Start Conditions | Manual only (déclenché par le pipeline Bitbucket) |
Configuration du workflow -> App Store Connect
Dans App Store Connect → Xcode Cloud → Manage Workflows → cliquer sur le workflow → copier l'ID affiché dans l'URL (format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX).
Ajouter cet ID comme variable ASC_WORKFLOW_ID_PREPROD dans Bitbucket.
Vous pourrez ensuite modifier votre workflow pour ajouter les paramètres suivants depuis App Store Connect (Edit Workflow) :
| Paramètre | Valeur |
|---|---|
| Build Number | ⚠️ "auto-increment" |
| Post-Actions | TestFlight Distribution → sélectionner les groupes de testeurs |
3.3 Script asc.rb — Client API App Store Connect
Script Ruby pur (pas de gem externe) qui :
- Génère des tokens JWT ES256 signés avec la clé
.p8 - Communique avec l'API REST App Store Connect v1
Commandes disponibles
# Lister les workflows Xcode Cloud d'une app
ruby scripts/asc.rb list-workflows fr.doing.starter
# Lister les branches connues de Xcode Cloud pour un workflow
ruby scripts/asc.rb list-refs <workflow_id>
# Résoudre un nom de branche en ref ID
ruby scripts/asc.rb resolve-ref <workflow_id> develop
# Déclencher un build en résolvant automatiquement la branche
ruby scripts/asc.rb trigger-branch <workflow_id> develop
Recherche de la clé .p8
Le script cherche AuthKey_<KEY_ID>.p8 dans cet ordre :
./private_keys/~/.appstoreconnect/private_keys/~/private_keys/
Variables par environnement
Dans le pipeline, les variables ASC_KEY_ID et ASC_ISSUER_ID sont exportées directement depuis les variables Bitbucket spécifiques à chaque env :
# Preprod
export ASC_KEY_ID="$ASC_KEY_ID_PREPROD" ASC_ISSUER_ID="$ASC_ISSUER_ID_PREPROD"
En local (via Makefile), le mécanisme utilise ASC_ENV avec un fallback :
ASC_ENV=PREPROD → ASC_KEY_ID_PREPROD (si défini) → sinon ASC_KEY_ID
ASC_ENV=PROD → ASC_KEY_ID_PROD (si défini) → sinon ASC_KEY_ID
3.4 Étape pipeline : déclenchement Xcode Cloud
- step: &deploy-ios-preprod
name: '🍎 iOS preprod → Xcode Cloud'
image: ghcr.io/cirruslabs/flutter:3.38.5
script:
- mkdir -p private_keys
- printf '%s' "$ASC_PRIVATE_KEY_B64_PREPROD" | base64 -d > "private_keys/AuthKey_${ASC_KEY_ID_PREPROD}.p8"
- export ASC_KEY_ID="$ASC_KEY_ID_PREPROD" ASC_ISSUER_ID="$ASC_ISSUER_ID_PREPROD"
- ruby scripts/asc.rb trigger-branch "$ASC_WORKFLOW_ID_PREPROD" "$BITBUCKET_BRANCH"
3.5 Résolution dynamique de branche
Le pipeline passe $BITBUCKET_BRANCH à asc.rb trigger-branch. Le script :
- Récupère le workflow → son repository ID
- Liste les
gitReferencesdu repository - Cherche la branche par nom exact
- Si trouvée → déclenche le build sur cette branche
- Si non trouvée (branche pas encore synchronisée) → déclenche sur la branche par défaut du workflow (avec un warning)
3.6 Scripts CI Xcode Cloud
Les scripts doivent être dans ios/ci_scripts/ (relativement au .xcworkspace).
ci_post_clone.sh — Après le clone
Ce script prépare l'environnement Flutter dans Xcode Cloud :
#!/bin/sh
set -e
FLUTTER_VERSION="3.38.5"
FLUTTER_DIR="$HOME/flutter"
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
# ─── 1. Installer Flutter (détection arm64 / x86_64) ─────────────────────────
echo "==> Installation de Flutter $FLUTTER_VERSION"
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
FLUTTER_URL="https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_arm64_${FLUTTER_VERSION}-stable.zip"
else
FLUTTER_URL="https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_${FLUTTER_VERSION}-stable.zip"
fi
curl -fsSL -o /tmp/flutter.zip "$FLUTTER_URL"
unzip -q /tmp/flutter.zip -d "$HOME"
rm /tmp/flutter.zip
export PATH="$FLUTTER_DIR/bin:$PATH"
echo "==> $(flutter --version | head -1)"
# ─── 2. Désactiver la télémétrie ─────────────────────────────────────────────
flutter config --no-analytics --suppress-analytics 2>/dev/null || true
# ─── 3. Générer Generated.xcconfig ───────────────────────────────────────────
cd "$REPO_ROOT"
echo "==> flutter pub get (répertoire : $REPO_ROOT)"
flutter pub get
# flutter pub get ne génère pas toujours Generated.xcconfig en CI.
# On le crée manuellement si absent — suffisant pour pod install.
mkdir -p ios/Flutter
if [ ! -f "ios/Flutter/Generated.xcconfig" ]; then
echo "==> Generated.xcconfig absent — création manuelle"
cat > ios/Flutter/Generated.xcconfig << XCCONFIG
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=${FLUTTER_DIR}
FLUTTER_APPLICATION_PATH=${REPO_ROOT}
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_MODE=release
DART_DEFINES=
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=false
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json
XCCONFIG
fi
echo "==> Generated.xcconfig :"
cat ios/Flutter/Generated.xcconfig
# ─── 4. Installer les dépendances CocoaPods ──────────────────────────────────
echo "==> pod install"
cd "$REPO_ROOT/ios"
pod install
- Ne pas utiliser
sudo— Xcode Cloud n'a pas de terminal interactif,sudoéchoue silencieusement. - Ne pas ajouter
--repo-updateàpod install— le Source CDN CocoaPods expire en SSL sur ces machines. - Ne pas activer
flutterfire_clisans Firebase — l'activation télécharge 200+ packages et provoque un timeout de 15 min. - Détecter l'architecture avec
uname -m— les machines Xcode Cloud peuvent être arm64 ou x86_64, une URL fixe échoue sur l'une des deux.
ci_pre_xcodebuild.sh — Avant la compilation
Ce script synchronise le build number Xcode avec celui de pubspec.yaml :
#!/bin/sh
set -e
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
# Extraire le build number depuis la ligne "version: 1.0.0+1" de pubspec.yaml
BUILD_NUMBER=$(grep '^version:' "$REPO_ROOT/pubspec.yaml" | sed 's/.*+//' | tr -d '[:space:]')
if [ -z "$BUILD_NUMBER" ]; then
echo "warning: build number introuvable dans pubspec.yaml — conservation du numéro actuel"
exit 0
fi
echo "==> Build number pubspec.yaml : $BUILD_NUMBER"
cd "$REPO_ROOT/ios"
agvtool new-version -all "$BUILD_NUMBER"
echo "==> CURRENT_PROJECT_VERSION mis à jour : $BUILD_NUMBER"
Xcode Cloud doit utiliser -workspace Runner.xcworkspace (et non -project Runner.xcodeproj) pour que CocoaPods soit inclus dans le graphe de dépendances. Si le workflow a été créé avant que pod install ne soit exécuté, il faut ouvrir le workflow dans Xcode → Product → Xcode Cloud → Manage Workflows → éditer → sauvegarder pour forcer la re-détection du workspace.
Partie 4 — Le fichier bitbucket-pipelines.yml complet
Voici la structure complète du fichier de pipelines :
definitions:
caches:
pub-cache: ~/.pub-cache
android-sdk: /opt/android-sdk
steps:
# ─── Mobile: Android ─────────────────────────────────────────────────────
- step: &deploy-android-preprod
name: '🤖 Android preprod → Play Store (internal)'
image: ghcr.io/cirruslabs/flutter:3.38.5
size: 2x
caches:
- gradle
- android-sdk
- pub-cache
script:
- gem install fastlane --no-document -q
- mkdir -p private_keys android
- printf '%s' "$GOOGLE_PLAY_JSON_KEY_B64_PREPROD" | base64 -d > private_keys/google-play-key.json
- printf '%s' "$ANDROID_KEYSTORE_B64_PREPROD" | base64 -d > android/upload-key.keystore
- printf '%s' "$ANDROID_KEY_PROPERTIES_B64_PREPROD" | base64 -d > android/key.properties
- make deploy-android-preprod FLUTTER=flutter DART=dart GOOGLE_PLAY_JSON_KEY=$(pwd)/private_keys/google-play-key.json
artifacts:
- build/app/outputs/bundle/preprodRelease/**
# ─── Mobile: iOS (Xcode Cloud) ──────────────────────────────────────────
- step: &deploy-ios-preprod
name: '🍎 iOS preprod → Xcode Cloud'
image: ghcr.io/cirruslabs/flutter:3.38.5
script:
- mkdir -p private_keys
- printf '%s' "$ASC_PRIVATE_KEY_B64_PREPROD" | base64 -d > "private_keys/AuthKey_${ASC_KEY_ID_PREPROD}.p8"
- export ASC_KEY_ID="$ASC_KEY_ID_PREPROD" ASC_ISSUER_ID="$ASC_ISSUER_ID_PREPROD"
- ruby scripts/asc.rb trigger-branch "$ASC_WORKFLOW_ID_PREPROD" "$BITBUCKET_BRANCH"
pipelines:
# Tests automatiques sur chaque PR
pull-requests:
'**':
- step:
name: Tests
image: ghcr.io/cirruslabs/flutter:3.38.5
script:
- flutter pub get
- flutter analyze
- flutter test
custom:
deploy-android-preprod:
- step: *deploy-android-preprod
deploy-ios-preprod:
- step: *deploy-ios-preprod
deploy-all-preprod:
- step: *deploy-android-preprod
- step: *deploy-ios-preprod
Dépannage
Android
| Problème | Cause | Solution |
|---|---|---|
| "The Android App Bundle was signed with the wrong key" | Variables ANDROID_KEYSTORE_B64_* / ANDROID_KEY_PROPERTIES_B64_* ne correspondent pas au keystore Play Store | Ré-encoder les bons fichiers avec base64 -i |
| "Only releases with status draft may be created on draft app" | L'app n'a jamais été publiée sur le Play Store — elle est encore au statut draft et n'accepte que release_status=draft | Voir § 2.7 Premier déploiement Android : ajouter ANDROID_RELEASE_STATUS=draft au lancement ou via la variable Makefile |
| "Container exceeded memory limit" | Build Gradle dépasse la RAM | Vérifier size: 2x dans le pipeline + -Xmx ≤ 3g dans gradle.properties |
| "Gradle build daemon disappeared unexpectedly" | Même cause | Idem ci-dessus |
iOS
| Problème | Cause | Solution |
|---|---|---|
| "Post-Clone script not found" | Scripts au mauvais emplacement | Placer dans ios/ci_scripts/ (pas ci_scripts/ à la racine) |
| "Generated.xcconfig: No such file or directory" | flutter pub get non exécuté | Vérifier ci_post_clone.sh dans les logs Xcode Cloud |
| "curl: (56) URL returned error: 404" | URL Flutter obsolète | Vérifier le format dans ci_post_clone.sh (.zip et non .tar.xz) |
| "Bad CPU type in executable" | Flutter arm64 téléchargé sur machine x86_64 (ou inversement) | Utiliser la détection uname -m dans ci_post_clone.sh pour choisir l'archive correcte |
| "sudo: a password is required" | sudo utilisé dans un script Xcode Cloud (pas de terminal interactif) | Supprimer tout appel sudo — ne pas utiliser sudo ln -sf pour Flutter |
| Post-clone timeout (≈15 min, pas d'erreur visible) | flutter pub global activate flutterfire_cli télécharge 200+ packages silencieusement | Supprimer cette ligne si le projet n'utilise pas Firebase |
| "Couldn't determine repo type — Operation timed out SSL" | pod install --repo-update tente une mise à jour du CDN CocoaPods qui expire en SSL | Utiliser pod install sans --repo-update |
| "Module 'connectivity_plus' not found" (exit code 65) | Xcode Cloud archive avec -project Runner.xcodeproj au lieu de -workspace → pods exclus du graphe | Ouvrir Xcode → Product → Xcode Cloud → Manage Workflows, éditer le workflow et sauvegarder pour forcer la re-détection de Runner.xcworkspace |
| Build uniquement dans "Internes" | Pas de post-action distribution | Ajouter TestFlight Distribution dans le workflow Xcode Cloud |
| "'' could not be added to xcode cloud" | 500 côté Apple | Relancer la commande — erreur intermittente sans solution connue |
Général
| Problème | Cause | Solution |
|---|---|---|
| "Variable XXX manquante" | Variable non configurée | Vérifier Dépôt → Paramètres → Variables dans Bitbucket |
Tests de validation
| Pipeline | Commande Bitbucket | Résultat attendu |
|---|---|---|
| Android preprod | Custom: deploy-android-preprod | AAB uploadé sur Play Store track internal |
| iOS preprod | Custom: deploy-ios-preprod | Build Xcode Cloud déclenché → TestFlight |
| Tests PR | Automatique sur PR | flutter analyze + flutter test passent |
Checklist
| Point | OK |
|---|---|
Variables Bitbucket Android configurées (GOOGLE_PLAY_JSON_KEY_B64_*, ANDROID_KEYSTORE_B64_*, ANDROID_KEY_PROPERTIES_B64_*) | ☐ |
Variables Bitbucket iOS configurées (ASC_KEY_ID_*, ASC_ISSUER_ID_*, ASC_PRIVATE_KEY_B64_*, ASC_WORKFLOW_ID_*) | ☐ |
| Compte de service Google Play créé et autorisé (preprod + prod) | ☐ |
| Clé API App Store Connect créée et encodée (preprod + prod) | ☐ |
| Workflow Xcode Cloud créé avec Build Number → Auto-increment | ☐ |
| Workflow ID récupéré et ajouté dans Bitbucket | ☐ |
Script ios/ci_scripts/ci_post_clone.sh présent et exécutable | ☐ |
Script ios/ci_scripts/ci_pre_xcodebuild.sh présent et exécutable | ☐ |
Workflow Xcode Cloud sauvegardé depuis Xcode après pod install (pour que l'archive utilise -workspace et non -project) | ☐ |
Premier deploy Android fait avec ANDROID_RELEASE_STATUS=draft | ☐ |
| Pipeline Android testé (≈10 min) | ☐ |
| Pipeline iOS testé (≈13 min total) | ☐ |
FAQ spécifique Flutter
Pourquoi des custom pipelines manuels et pas des triggers automatiques ?
Pour garder le contrôle sur le moment du déploiement. Les tests automatiques tournent sur chaque PR, mais le déploiement sur les stores est déclenché volontairement après validation.
Pourquoi Xcode Cloud pour iOS au lieu d'un runner macOS ?
Bitbucket Pipelines n'offre pas de runners macOS. Xcode Cloud est inclus gratuitement dans l'Apple Developer Program (25h/mois) et gère le build, la signature et l'upload vers TestFlight.
Pourquoi size: 2x pour Android seulement ?
Gradle + Flutter consomment beaucoup de RAM (> 4 Go). Le pipeline iOS ne build rien (simple appel API REST vers Xcode Cloud). Seul Android nécessite les 8 Go.
Comment passer d'un track internal à production pour Android ?
Ajouter la variable ANDROID_TRACK=production au lancement du pipeline, ou utiliser make deploy-android-prod ANDROID_TRACK=production.
Comment ajouter un nouveau groupe de testeurs TestFlight ?
Dans App Store Connect → Xcode Cloud → Workflow → modifier les Post-Actions → TestFlight Distribution → ajouter le groupe souhaité.