Android- und iOS-Apps in einer CI-Pipeline bauen
Sie haben eine mobile App, die auf Ihrem Laptop einwandfrei kompiliert. Sie pushen den Code ins Repository, die CI-Pipeline startet, und zehn Minuten später bricht sie mit einem Fehler ab, den Sie noch nie gesehen haben. Die SDK-Version ist anders. Eine Abhängigkeit wurde in einer etwas neueren Version aufgelöst. Das Signaturzertifikat fehlt. Das ist die Realität von Mobile Builds in CI: Was lokal funktioniert, bricht in der Pipeline oft auseinander.
Das Erste, was in einer mobilen CI-Pipeline richtig sein muss, ist der Build-Prozess selbst. Nicht nur das Ausführen des Compilers, sondern die Erstellung eines Artefakts, das konsistent, testbar und für die Verteilung bereit ist. Android und iOS handhaben das unterschiedlich, und jedes hat seine eigenen Fallstricke.
Android-Builds mit Gradle
Android-Builds laufen über Gradle, das die Konfiguration aus build.gradle-Dateien liest. Drei SDK-Einstellungen sind hier wichtig: compileSdk, minSdk und targetSdk. Sie sind leicht zu verwechseln, aber jede hat einen eigenen Zweck.
compileSdk steuert, welche API-Ebene während der Kompilierung verfügbar ist. Wenn Sie es auf 34 setzen, können Sie APIs verwenden, die in Android 14 eingeführt wurden. minSdk ist die niedrigste Android-Version, die Ihre App unterstützt. Wenn Sie es auf 26 setzen, können Geräte mit Android 8.0 oder älter Ihre App nicht installieren. targetSdk teilt Android mit, welche Version Sie getestet haben. Wenn Sie auf ein neueres SDK abzielen, kann Android Verhaltensänderungen anwenden, die Ihre App betreffen.
Die Pipeline muss dieselben SDK-Versionen verwenden wie Ihre lokale Entwicklungsumgebung. Eine Abweichung führt oft zu Kompilierungsfehlern, die nur in CI auftreten. Legen Sie diese Versionen explizit in Ihren build.gradle-Dateien fest und überprüfen Sie sie in der Pipeline-Konfiguration.
Abhängigkeiten sind eine weitere häufige Fehlerquelle. Gradle zieht Bibliotheken von Maven Central, Google Maven oder Ihrem internen Repository. Ohne Caching lädt die Pipeline bei jedem Build jede Abhängigkeit von Grund auf neu herunter. Ein Projekt mit zwanzig Abhängigkeiten kann zehn bis fünfzehn Minuten nur für das Herunterladen benötigen. Cachen Sie das Gradle-Abhängigkeitsverzeichnis zwischen den Builds. Die meisten CI-Plattformen unterstützen dies mit einer einfachen Konfigurationsänderung, und es verkürzt die Build-Zeit erheblich.
Das Ergebnis eines Android-Builds ist entweder eine APK oder eine AAB. APK ist das ältere Format, das Sie direkt auf einem Gerät installieren können. AAB ist das neuere Format, das Sie bei Google Play hochladen, das dann optimierte APKs für jede Gerätekonfiguration generiert. Verwenden Sie APK für interne Tests und manuelle Verteilung. Verwenden Sie AAB für offizielle Veröffentlichungen über den Play Store. Ihre Pipeline sollte beide unterstützen, aber die Wahl hängt davon ab, wohin das Artefakt geht.
Hier ist ein minimales GitHub Actions-Job, das eine Android-App baut und die APK als Artefakt speichert:
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
Dieses Beispiel richtet JDK ein, aktiviert Gradle-Caching, führt den Release-Build aus und lädt die resultierende APK hoch. Passen Sie die Java-Version und den Gradle-Wrapper-Pfad an Ihr Projekt an.
iOS-Builds mit Xcode
iOS-Builds verwenden Xcode und sein Build-System. Die Pipeline führt xcodebuild mit Parametern aus, die das Scheme, die Konfiguration (Debug oder Release) und das Ziel (Simulator oder physisches Gerät) angeben. Die Projektdatei ist entweder .xcodeproj oder .xcworkspace. Wenn Ihr Projekt CocoaPods verwendet, benötigen Sie die Workspace-Datei.
Abhängigkeitsmanagement ist der Punkt, an dem iOS-Builds oft scheitern. Viele iOS-Projekte verwenden CocoaPods, Swift Package Manager oder Carthage. Die Pipeline muss pod install oder swift package resolve vor dem Build ausführen. Wenn die in CI aufgelösten Versionen von denen abweichen, die Ihr Team lokal verwendet, erhalten Sie Fehler, die schwer zu debuggen sind. Fixieren Sie Ihre Abhängigkeitsversionen. CocoaPods generiert eine Podfile.lock-Datei. Committen Sie sie in das Repository und stellen Sie sicher, dass die Pipeline sie verwendet.
Das Ergebnis eines iOS-Builds ist eine IPA-Datei. Im Gegensatz zu einer APK ist eine IPA ein Bundle, das die signierte Anwendung enthält. Pipelines produzieren typischerweise zwei Varianten: eine Entwicklungs-IPA für interne Tests mit Entwicklerzertifikaten und eine Distributions-IPA für den App Store. Beide benötigen eine ordnungsgemäße Signierung, die wir separat behandeln werden.
Speichern von Build-Artefakten
Sowohl Android- als auch iOS-Builds produzieren Artefakte, die gespeichert werden müssen. Der einfachste Ansatz ist die Verwendung des in Ihre CI-Plattform integrierten Artefaktspeichers. Für größere Teams oder komplexere Workflows laden Sie Artefakte an einen gemeinsamen Speicherort wie S3 oder Google Cloud Storage hoch.
Das folgende Diagramm zeigt, wie die Android- und iOS-Build-Pipelines parallel laufen und im Artefaktspeicher zusammenlaufen.
Jedes Artefakt benötigt eine eindeutige Kennung. Fügen Sie die Versionsnummer und die Build-Nummer in den Dateinamen oder die Metadaten ein. Sie sollten jedes Artefakt auf den genauen Commit zurückverfolgen können, der es erzeugt hat. Ohne dies wird das Debuggen eines Produktionsproblems zur Ratespiel.
Praktische Checkliste
Bevor Sie Ihre mobile Build-Pipeline für bereit erklären, gehen Sie diese kurze Checkliste durch:
- SDK-Versionen in
build.gradlestimmen zwischen lokaler Umgebung und CI überein - Gradle-Abhängigkeits-Caching ist aktiviert
Podfile.lockoder Äquivalent ist eingecheckt und wird in CI verwendet- Xcode-Scheme und -Konfiguration sind in der Pipeline explizit gesetzt
- Artefakt-Dateinamen enthalten Versions- und Build-Nummer
- Build-Artefakte werden gespeichert und sind nach Abschluss der Pipeline zugänglich
Das Fazit
Eine mobile Build-Pipeline dreht sich nicht nur darum, einen Compiler auszuführen. Es geht darum, jedes Mal dieselbe Umgebung, dieselben Abhängigkeiten und dieselbe Konfiguration zu reproduzieren. Wenn Ihr lokaler Build funktioniert, die Pipeline aber fehlschlägt, liegt das Problem fast immer an einem Unterschied in einem dieser drei Dinge. Fixieren Sie sie, cachen Sie aggressiv und benennen Sie Ihre Artefakte klar. Der Rest der Pipeline hängt davon ab, diesen ersten Schritt richtig zu machen.