Android applicatie CI/CD met Flutter

Dit artikel is meer dan een jaar geleden gepubliceerd. De informatie kan verouderd zijn.
CI/CD pipeline is een essentieel onderdeel van softwareontwikkeling. In dit artikel wordt uitgelegd hoe u een CI/CD pipeline construeert om een Android applicatie Flutter . We bouwen een pijplijn op basis van GitHub Actions en gebruiken geen fastlane .
1. Bouw lokaal
Laten we lokaal een app bouwen voordat we een pijplijn op GitHub
U kunt een build-omgeving voorbereiden met de officiële website - Build and release an Android app.
We zullen hier een deel van de inhoud uitleggen.
1-1. key.jks en key.properties
Voor het bouwen van een Android app is de sleutel nodig om te ondertekenen. key.jks bevat de sleutel en key.properties bevat het wachtwoord.
key.jks kan worden gegenereerd door de onderstaande commando's.
ramen
1keytool -genkey -v -keystore c:\Users\USER_NAME\key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias keyMac / Linux
1keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias keyAls u deze opdrachten gebruikt, heeft u een key password en store password .
Noteer deze wachtwoorden in het bestand key.properties
1storePassword=<your password>2keyPassword=<your password>3keyAlias=key4storeFile=C:/Users/USER_NAME/key.jks // depends on your environmentPas vervolgens de Android aan om deze bestanden te gebruiken om uw app te ondertekenen.
1-2. app / bundle.gradle
Fix bundle.gradle bestand. Merk op dat er twee bundle.gradle bestanden in het project zijn.
We gebruiken het bestand onder de app directory.
1def keystoreProperties = new Properties()2def keystorePropertiesFile = rootProject.file('key.properties')3if (keystorePropertiesFile.exists()) {4 keystoreProperties.load(new FileInputStream(keystorePropertiesFile))5}6 7android {8 signingConfigs {9 release {10 keyAlias keystoreProperties['keyAlias'] ? keystoreProperties['keyAlias'] : "key"11 keyPassword keystoreProperties['keyPassword'] ? keystoreProperties['keyPassword'] : "$System.env.KEY_PASSWORD"12 storeFile file("../key.jks")13 storePassword keystoreProperties['storePassword'] ? keystoreProperties['storePassword'] : "$System.env.STORE_PASSWORD"14 }15 }16 17 buildTypes {18 release {19 signingConfig signingConfigs.release20 }21 }22}Met het eerste blok kan de app het key.properties bestand lezen.
rootProject.file('key.properties') betekent het lezen van key.properties in de hoofdmap van het project.
Als u de bestandsnaam of directory niet wilt wijzigen, kunt u deze uitdrukking wijzigen.
Vervolgens kunnen we twee blokken zien onder het android blok.
signingConfigs beschrijft letterlijk de configuratie voor ondertekenen. U kunt hier de inhoud van key.properties .
keystoreProperties['keyPassword'] levert bijvoorbeeld keyPassword waarde uit het key.properties bestand.
$System.env.KEY_PASSWORD betekent dat u de waarde uit de systeemomgeving kunt halen. file("../key.jks") betekent dat u de belangrijkste gegevens rechtstreeks uit het bestand kunt laden.
U kunt elke gewenste uitdrukking kiezen.
Laten we vervolgens de app bouwen.
1flutter build apk --releaseU kunt met deze opdracht apk
De opdracht kan u waarschuwen om app bundle of split apk te gebruiken om dikke apk te vermijden, maar negeer ze nu alstublieft. Ik zal het later uitleggen.
2. Registreer geheimen op GitHub
Registreer de nodige geheimen op GitHub . We hebben in ieder geval onderstaande geheimen nodig. Zie Encrypted Secrets om te zien hoe je geheimen registreert op GitHub .
- key wachtwoord
- wachtwoord opslaan
- key.jks
Als u binaire bestanden zoals key.jks , hebt u base64-codering nodig om een geheime string te genereren. Vergeet niet om het te decoderen wanneer u het in de pijplijn gebruikt.
U kunt ook andere geheime beheerservices gebruiken, zoals Azure KeyVault en GCP SecretManager .
Hoe dan ook, je moet de key.jks en alle andere geheimen scheiden van de broncode-repository en ze veilig bewaren.
3. Workflow toevoegen
Voeg een workflow toe met behulp van een yaml-bestand.
Maak een yaml-bestand zoals .github/workflows/xxx.yaml .
1name: CICD2 3on:4 pull_request:5 branches: [master]6 workflow_dispatch:7 8jobs:9 dev:10 runs-on: ubuntu-latest11 12 steps:13 # checkout source code14 - uses: actions/checkout@v215 # setup java16 - name: set up JDK 1.817 uses: actions/setup-java@v118 with:19 java-version: 1.820 # setup flutter21 - name: Setup flutter22 uses: subosito/flutter-action@v123 with:24 flutter-version: "2.0.1"25 # pub get26 - run: flutter pub get27 # analyze28 - run: flutter analyze29 # test30 - run: flutter test31 # build32 - name: build dev33 env:34 KEY_JKS: ${{ secrets.KEY_JKS }}35 KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}36 STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}37 GOOGLE_SERVICES: ${{ secrets.GOOGLE_SERVICES }}38 run: echo $KEY_JKS | base64 --decode --ignore-garbage > android/key.jks && flutter build apk --releaseIk sla de uitleg over Java instellingen, Flutter instellingen, pub get , analyze , test .
De bouwtaak bestaat uit een paar opdrachten die verband houden met && . Laten we een voor een kijken.
1echo $KEY_JKS | base64 --decode --ignore-garbage > android/key.jksDit commando houdt in dat het key.jks bestand uit geheimen wordt gegenereerd. Zoals ik heb uitgelegd, is key.jks geregistreerd als base64-gecodeerde tekenreeks, dus hier moeten we het decoderen en het key.jks bestand opnieuw genereren. Door het bestand te genereren, kan de app sleutelinformatie uit het bestand laden terwijl we het winkelbestand configureren als file("../key.jks") .
In de bouwtaak heb ik geen key.properties bestand gegenereerd. Dit komt doordat we keyPassword en storePassword configureren als $System.env.KEY_PASSWORD .
We hebben de omgeving ingesteld zoals hieronder, zodat de app het wachtwoord uit de systeemomgeving kan laden.
Als u het wachtwoord van key.properties wilt lezen, kunt u bundle.gradle wijzigen en het key.properties bestand hier in de build-taak genereren.
1- name: build dev2 env:3 KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}4 STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}Laten we vervolgens de build-opdracht bekijken.
1flutter build apk --releaseDit is volledig hetzelfde als lokale build. U ziet dus waarschuwingen die u vertellen dat u app bundle of split apk moet gebruiken om dikke apk te vermijden.
Volgens de officiële site Building the app for release wordt een app bundle aanbevolen. Dus wanneer u de app vrijgeeft, is het beter om een app bundle te bouwen, maar wanneer u de app op uw apparaat test of App Distribute van Firebase , heeft u apk nodig.
Dus ik raad aan om de manier te kiezen om uw app te bouwen op basis van het doel. Als dagelijkse CI build kunt u bijvoorbeeld apk genereren waarmee u eenvoudig op uw apparaat kunt testen, en als release-build kunt u een app bundle genereren en de app registreren in Google Play Store .
Onderstaande voorbeelden bieden beide typen build.
Registreer een app bij App Distribution
1name: CICD2 3on:4 pull_request:5 branches: [master]6 workflow_dispatch:7 8jobs:9 dev:10 runs-on: ubuntu-latest11 12 steps:13 # checkout source code14 - uses: actions/checkout@v215 # setup java16 - name: set up JDK 1.817 uses: actions/setup-java@v118 with:19 java-version: 1.820 # setup flutter21 - name: Setup flutter22 uses: subosito/flutter-action@v123 with:24 flutter-version: "2.0.1"25 # pub get26 - run: flutter pub get27 # analyze28 - run: flutter analyze29 # test30 - run: flutter test31 # build32 - name: build33 env:34 KEY_JKS: ${{ secrets.KEY_JKS }}35 KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}36 STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}37 GOOGLE_SERVICES: ${{ secrets.GOOGLE_SERVICES }}38 run: echo $KEY_JKS | base64 --decode --ignore-garbage > android/key.jks && echo $GOOGLE_SERVICES > android/app/google-services.json && flutter build apk --release39 # app distribution40 - name: Firebase App Distribution41 uses: wzieba/Firebase-Distribution-Github-Action@v1.2.242 with:43 appId: ${{secrets.FIREBASE_APP_ID}}44 token: ${{secrets.FIREBASE_APP_TOKEN}}45 file: build/app/outputs/apk/release/app-release.apk46 groups: TesterRegistreer een app bij Google Play Store
1name: Release2 3on:4 workflow_dispatch:5 6jobs:7 dev:8 runs-on: ubuntu-latest9 10 steps:11 # checkout source code12 - uses: actions/checkout@v213 # setup java14 - name: set up JDK 1.815 uses: actions/setup-java@v116 with:17 java-version: 1.818 # setup flutter19 - name: Setup flutter20 uses: subosito/flutter-action@v121 with:22 flutter-version: "2.0.1"23 # pub get24 - run: flutter pub get25 # analyze26 - run: flutter analyze27 # test28 - run: flutter test29 # build30 - name: build31 env:32 KEY_JKS: ${{ secrets.KEY_JKS }}33 KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}34 STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}35 GOOGLE_SERVICES: ${{ secrets.GOOGLE_SERVICES }}36 run: echo $KEY_JKS | base64 --decode --ignore-garbage > android/key.jks && flutter build appbundle --obfuscate --split-debug-info=build/app/outputs/symbols --release37 # google play38 - name: Create service account json39 env:40 SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON}}41 run: echo $SERVICE_ACCOUNT_JSON > android/app/service-account.json42 - uses: r0adkll/upload-google-play@v143 with:44 serviceAccountJson: android/app/service-account.json45 packageName: your app id46 releaseFiles: build/app/outputs/bundle/release/app-release.aab47 track: alpha48 whatsNewDirectory: release-notes49 mappingFile: build/app/outputs/mapping/release/mapping.txt4. Andere opties
4-1. Firebase google-services.json
1echo $GOOGLE_SERVICES > android/app/google-services.jsonOm verbinding te maken met Firebase , heeft u google-services.json .
U kunt de json genereren met het bovenstaande commando.
Voor meer details, zie FlutterFire - Android-installatie.
4-2. App Distribution
App Distribution is een van de functies die Firebase biedt.
Met deze functie kunt u de app aan testers leveren. Als u deze functie wilt gebruiken, voegt u gewoon de onderstaande taak toe aan de pijplijn.
1- name: Firebase App Distribution2 uses: wzieba/Firebase-Distribution-Github-Action@v1.2.23 with:4 appId: your app id5 token: ${{secrets.FIREBASE_APP_TOKEN}}6 file: build/app/outputs/apk/release/app-release.apk7 groups: TesterZie Firebase Distribution Github Action voor meer informatie.
Merk op dat alleen apk bestanden zijn toegestaan voor App Distribution .
4-3. Product Flavor
Als u product flavor met Flutter , specificeer dan --flavor <flavor name> in build-opdracht.
Zie build varianten voor product flavor
1flutter build appbundle --obfuscate --split-debug-info=build/app/outputs/symbols --release --flavor jpMet flavor kun je verschillende app-id's genereren met dezelfde code.
1android {2 3 defaultConfig {4 applicationId "xxx.yyy.zzz"5 ...6 }7 8 flavorDimensions "targetArea"9 productFlavors {10 jp {11 applicationIdSuffix ".jp"12 dimension "targetArea"13 }14 eu {15 applicationIdSuffix ".eu"16 dimension "targetArea"17 }18 }Met flavor is de app-ID de combinatie van applicationId en applicationIdSuffix .
Als u bijvoorbeeld --flavor jp opgeeft, is de app-ID xxx.yyy.zzz.jp
U kunt het manifestbestand ook wijzigen met flavor .
Stel dat u Google AdMob gaat gebruiken, dan moet u applicationId aan het manifestbestand toevoegen.
U kunt dit doen door manifestbestanden in te stellen zoals hieronder.
1android/app/src2 |- main/AndroidManifest.xml3 |- jp/AndroidManifest.xml4 |- eu/AndroidManifest.xmlZet het basismanifestbestand op android/app/src/main , en plaats vervolgens elk flavor manifestbestand op android/app/src/<flavor name>
De vervolgens gebouwde app bevat zowel het hoofdmanifest als het smaakmanifest.
1<manifest xmlns:android="http://schemas.android.com/apk/res/android"2 package="xxx.yyy.zzz">3 <uses-permission android:name="android.permission.INTERNET" />4 <application>5 <meta-data6 android:name="com.google.android.gms.ads.APPLICATION_ID"7 android:value="your admob app id"/>8 </application>9</manifest>4-4. --dart-definiëren
Met deze optie kunt u omgevingsvariabelen doorgeven aan de app.
1flutter build appbundle --obfuscate --split-debug-info=build/app/outputs/symbols --release --flavor jp --dart-define=REGION=asia-northeast1Deze opdracht genereert een omgeving met de naam REGION die bijvoorbeeld de regio van de backend-server beschrijft.
De app kan de omgeving lezen aan de hand van onderstaande code.
1String region = String.fromEnvironment('REGION'); // get 'asia-northeast1'4-5. Registreer een app bij Google Play Store
Gebruik deze taak als u uw app bij Google Play Store
1- name: Create service account json2 env:3 SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON}}4 run: echo $SERVICE_ACCOUNT_JSON > android/app/service-account.json5- uses: r0adkll/upload-google-play@v16 with:7 serviceAccountJson: android/app/service-account.json8 packageName: your app id9 releaseFiles: build/app/outputs/bundle/release/app-release.aab10 track: alpha11 whatsNewDirectory: release-notes12 mappingFile: build/app/outputs/mapping/release/mapping.txtDe eerste taak genereert service-account.json die nodig is om toegang te krijgen tot de Play Store vanaf de CI server.
Specificeer vervolgens dit bestand in de tweede taak.
Zie upload google play voor meer informatie.
Referenties
Een Android-app bouwen en vrijgeven
FlutterFire - Android-installatie



