Créer des applications Android et iOS dans un pipeline CI

Vous avez une application mobile qui compile parfaitement sur votre machine. Vous poussez le code dans le dépôt, le pipeline CI démarre, et dix minutes plus tard, il échoue avec une erreur que vous n'avez jamais vue. La version du SDK est différente. Une dépendance a résolu une version légèrement plus récente. Le certificat de signature est manquant. C'est la réalité des builds mobiles en CI : ce qui fonctionne en local casse souvent dans un pipeline.

La première chose à maîtriser dans un pipeline CI mobile est le processus de build lui-même. Pas seulement lancer le compilateur, mais produire un artefact cohérent, testable et prêt pour la distribution. Android et iOS gèrent cela différemment, et chacun a ses propres pièges.

Builds Android avec Gradle

Les builds Android s'exécutent via Gradle, qui lit la configuration depuis les fichiers build.gradle. Trois paramètres SDK sont importants : compileSdk, minSdk et targetSdk. Ils sont faciles à confondre, mais chacun a un rôle distinct.

compileSdk contrôle le niveau d'API disponible lors de la compilation. Si vous le définissez sur 34, vous pouvez utiliser les API introduites dans Android 14. minSdk est la version Android minimale que votre application supporte. Si vous le définissez sur 26, les appareils sous Android 8.0 ou antérieur ne peuvent pas installer votre application. targetSdk indique à Android la version que vous avez testée. Lorsque vous ciblez un SDK plus récent, Android peut appliquer des changements de comportement qui affectent votre application.

Le pipeline doit utiliser les mêmes versions de SDK que votre environnement de développement local. Une différence provoque souvent des erreurs de compilation qui n'apparaissent qu'en CI. Épinglez ces versions explicitement dans vos fichiers build.gradle et vérifiez-les dans la configuration du pipeline.

Les dépendances sont une autre source fréquente de problèmes. Gradle télécharge les bibliothèques depuis Maven Central, Google Maven ou votre dépôt interne. Sans mise en cache, le pipeline télécharge chaque dépendance depuis zéro à chaque build. Un projet avec vingt dépendances peut passer dix à quinze minutes rien qu'à télécharger. Mettez en cache le répertoire des dépendances Gradle entre les builds. La plupart des plateformes CI le permettent avec une simple modification de configuration, ce qui réduit considérablement le temps de build.

Le résultat d'un build Android est soit un APK, soit un AAB. L'APK est l'ancien format que vous pouvez installer directement sur un appareil. L'AAB est le nouveau format que vous téléchargez sur Google Play, qui génère ensuite des APK optimisés pour chaque configuration d'appareil. Utilisez l'APK pour les tests internes et la distribution manuelle. Utilisez l'AAB pour les versions officielles via le Play Store. Votre pipeline doit supporter les deux, mais le choix dépend de la destination de l'artefact.

Voici un exemple minimal de job GitHub Actions qui construit une application Android et stocke l'APK comme artefact :

name: Android Build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'
      - name: Cache Gradle dependencies
        uses: actions/cache@v4
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Build release APK
        run: ./gradlew assembleRelease
      - name: Upload APK
        uses: actions/upload-artifact@v4
        with:
          name: app-release
          path: app/build/outputs/apk/release/*.apk

Cet exemple configure JDK, active la mise en cache Gradle, exécute le build release et télécharge l'APK résultant. Ajustez la version Java et le chemin du wrapper Gradle pour correspondre à votre projet.

Builds iOS avec Xcode

Les builds iOS utilisent Xcode et son système de build. Le pipeline exécute xcodebuild avec des paramètres qui spécifient le scheme, la configuration (Debug ou Release) et la destination (simulateur ou appareil physique). Le fichier projet est soit .xcodeproj soit .xcworkspace. Si votre projet utilise CocoaPods, vous avez besoin du fichier workspace.

La gestion des dépendances est l'endroit où les builds iOS échouent souvent. De nombreux projets iOS utilisent CocoaPods, Swift Package Manager ou Carthage. Le pipeline doit exécuter pod install ou swift package resolve avant de compiler. Si les versions résolues en CI diffèrent de celles utilisées par votre équipe en local, vous obtenez des erreurs difficiles à déboguer. Verrouillez les versions de vos dépendances. CocoaPods génère un fichier Podfile.lock. Commitez-le dans le dépôt et assurez-vous que le pipeline l'utilise.

Le résultat d'un build iOS est un fichier IPA. Contrairement à un APK, un IPA est un bundle qui contient l'application signée. Les pipelines produisent généralement deux variantes : un IPA de développement pour les tests internes avec des certificats de développement, et un IPA de distribution pour l'App Store. Les deux nécessitent une signature appropriée, que nous aborderons séparément.

Stockage des artefacts de build

Les builds Android et iOS produisent tous deux des artefacts qui doivent être stockés. L'approche la plus simple consiste à utiliser le stockage d'artefacts intégré à votre plateforme CI. Pour les équipes plus importantes ou les workflows plus complexes, téléchargez les artefacts vers un emplacement partagé comme S3 ou Google Cloud Storage.

Le diagramme suivant montre comment les pipelines de build Android et iOS s'exécutent en parallèle et convergent vers le stockage d'artefacts.

flowchart TD A[Récupération du code] --> B[Android: Build Gradle] A --> C[iOS: Build Xcode] B --> D[APK / AAB] C --> E[IPA] D --> F[Stockage d'artefacts] E --> F F --> G[Version et numéro de build]

Chaque artefact a besoin d'un identifiant clair. Incluez le numéro de version et le numéro de build dans le nom du fichier ou les métadonnées. Vous devez pouvoir tracer n'importe quel artefact jusqu'au commit exact qui l'a produit. Sans cela, déboguer un problème de production devient un jeu de devinettes.

Liste de vérification pratique

Avant de déclarer votre pipeline de build mobile prêt, parcourez cette courte liste de vérification :

  • Les versions SDK dans build.gradle correspondent entre l'environnement local et CI
  • La mise en cache des dépendances Gradle est activée
  • Podfile.lock ou équivalent est committé et utilisé en CI
  • Le scheme et la configuration Xcode sont explicitement définis dans le pipeline
  • Les noms de fichiers d'artefacts incluent la version et le numéro de build
  • Les artefacts de build sont stockés et accessibles après la fin du pipeline

Ce qu'il faut retenir

Un pipeline de build mobile ne se résume pas à exécuter un compilateur. Il s'agit de reproduire le même environnement, les mêmes dépendances et la même configuration à chaque fois. Quand votre build local fonctionne mais que le pipeline échoue, le problème vient presque toujours d'une différence dans l'un de ces trois éléments. Verrouillez-les, mettez en cache de manière agressive et nommez vos artefacts clairement. Le reste du pipeline dépend de la réussite de cette première étape.