This is a guide on how to build and deploy flutter hello world apps both iOS and Android from a private git repo. This is part 2 of the series for Android apps. The code will be built in Azure devops pipeline and will be deployed to firebase for distribution on test devices.
Lets create our second job in the azureops.yaml file to build our Android app. The azureops.yaml should like below
trigger:
- master
jobs:
- job: android
pool:
vmImage: "macos-latest"
variables:
- group: secrets
- group: general
- name: androidReleaseDir
value: $(build.artifactStagingDirectory)/build/app/outputs/flutter-apk
- name: apkFile
value: $(androidReleaseDir)/app-release.apk
steps:
- task: [email protected]
displayName: "Install Flutter"
inputs:
mode: "auto"
channel: "stable"
version: "custom"
customVersion: "2.2.3"
- task: [email protected]
inputs:
target: apk
projectDirectory: "."
buildNumber: ""
This should build an unsigned apk that we will sign and distribute in the next sections.
To sign the built apk, we need to generate a key using Android studio’s keytool cli app by running the command below on a command line.
keytool -genkey -v -keystore android-key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias helloworld-counterapp
This will prompt a few questions below, some questions are optional and can be skipped as well:
question | answer |
---|---|
Enter keystore password | abc123 |
What is your first and last name | Enter your fullname here |
What is the name of your organizational unit? | helloapps |
What is the two-letter country code for this unit | AU |
Enter key password for helloworld-counterapp | abc123 |
Note: Its probably better to have a separate password for keystore and the key password itself from a security standpoint.
Now upload the generated android-key.jks
file to our pipeline as a secure file and add the two variables below into the secrets group. For more info on how to secrets see the part-1 of this series.
variable | value |
---|---|
androidKeystorePassword | abc123 |
androidKeyPassword | abc123 |
Now add the following section to the azureops yaml to add the code signing steps
- task: [email protected]
displayName: "Signing and aligning APK file(s) **/*.apk"
inputs:
apkFiles: "**/*.apk"
apksign: true
apksignerKeystoreFile: android-key.jks
apksignerKeystorePassword: "$(androidKeystorePassword)"
apksignerKeystoreAlias: helloworld-counterapp
apksignerKeyPassword: "$(androidKeyPassword)"
- task: [email protected]
inputs:
contents: "**/*.apk"
targetFolder: "$(build.artifactStagingDirectory)"
- task: [email protected]
inputs:
artifactName: "drop"
To upload the signed apk to firebase, we need to Register an Android project in firebase.
Androd package name | app nickname |
---|---|
com.example.hello_world_counter_app | hellocounter android app |
Download the google-services.json
file as indicated on the console and place it next to build.gradle under the android folder as indicated on the screen and follow the wizard to the last step.
Note: Make sue to click “Get Started” on the new created app distribution project otherise the upload may fail.
Go back into the project settings and note the App ID of this android project we just setup and create that as variable under the Azure Devops pipeline general
group and call it androidFirebaseDistAppId
. With that inplace lets add the final step in the android job as below.
- task: [email protected]
displayName: "Upload to firebase app distribution"
inputs:
targetType: "inline"
script: |
npm i -g firebase-tools
ls -la $(androidReleaseDir)
firebase appdistribution:distribute "$(apkFile)" \
--app "$(androidFirebaseDistAppId)" \
--release-notes "From Azure Devops" \
--groups "beta-testers" \
--token "$(firebasetoken)"
This should upload the signed build to firebase and all the beta testers will be notified to download and test the app. Here’s the full file for reference.
trigger:
- master
jobs:
- job: android
pool:
vmImage: "macos-latest"
variables:
- group: secrets
- group: general
- name: androidReleaseDir
value: $(build.artifactStagingDirectory)/build/app/outputs/flutter-apk
- name: apkFile
value: $(androidReleaseDir)/app-release.apk
steps:
- task: [email protected]
displayName: "Install Flutter"
inputs:
mode: "auto"
channel: "stable"
version: "custom"
customVersion: "2.2.3"
- task: [email protected]
displayName: "Build unsigned APK"
inputs:
target: apk
projectDirectory: "."
buildNumber: ""
- task: [email protected]
displayName: "Signing and aligning APK file(s) **/*.apk"
inputs:
apkFiles: "**/*.apk"
apksign: true
apksignerKeystoreFile: android-key.jks
apksignerKeystorePassword: "$(androidKeystorePassword)"
apksignerKeystoreAlias: helloworld-counterapp
apksignerKeyPassword: "$(androidKeyPassword)"
- task: [email protected]
displayName: "Copy apk to artifact directory"
inputs:
contents: "**/*.apk"
targetFolder: "$(build.artifactStagingDirectory)"
- task: [email protected]
displayName: "Publish signed apk as artifact"
inputs:
artifactName: "drop"
- task: [email protected]
displayName: "Upload to firebase app distribution"
inputs:
targetType: "inline"
script: |
npm i -g firebase-tools
ls -la $(androidReleaseDir)
firebase appdistribution:distribute "$(apkFile)" \
--app "$(androidFirebaseDistAppId)" \
--release-notes "From Azure Devops" \
--groups "beta-testers" \
--token "$(firebasetoken)"