Deploy your Flutter App to Firebase App Distribution using GitHub Actions - Android

Firebase App Distribution is a great way to distribute your apps efficiently to your testers without making your app validated by Google or Apple.

But it can be even more powerful to automatically deploy your app each time you are making a change to your code so that you can test your app even more frequently.

Even if there are a lot of tools that can help automate everything, like CodeMagic or Bitrise, today I want to show you how to use GitHub Actions for deploying to Firebase App Distribution.

This first part will focus on Android. The second part (which will be longer thanks to the Apple process) will focus on iOS.

Why not use Fastlane

Fastlane is a tool that can help distribute your app to your store and your staging environment (Firebase App Distribution or AppCenter, for example). It can help your CI be fully platform agnostic, but I feel like fastfile is often too complicated for beginners.

Prepare your app

To publish your app on Firebase, you must sign your app. The first step is to create a Keystore. Using Android Studio, you can easily create one.

Go in Build > Generate Signed Bundles / APK; you can create one directly in the assistant.

Remember all the passwords and alias for your Keystore; you'll need them after!

Finally, you need to modify your app/build.gradle with this in your signingConfig.

signingConfigs {
    if (System.getenv("ANDROID_KEYSTORE_PATH")) {
        release {
            storeFile file(System.getenv("ANDROID_KEYSTORE_PATH"))
            keyAlias System.getenv("ANDROID_KEYSTORE_ALIAS")
            keyPassword System.getenv("ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD")
            storePassword System.getenv("ANDROID_KEYSTORE_PASSWORD")
        }
    } else {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
}

You say that you will be using a local key file if the variable ANDROID_KEYSTORE_PATH isn't defined. Otherwise, you'll be using the file, reading from environment variables.

The Github Workflow

A GitHub action workflow needs to be defined in a .github/workflows folder at the root of your project. I'll name mine deploy-android.yaml.

name: Deploy Android to Firebase App Distribution on merge
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - uses: subosito/flutter-action@v1.5.3

      - name: Install Dependencies
        run: flutter packages get

      - name: Decode Keystore
        id: write_file
        uses: timheuer/base64-to-file@v1
        with:
          fileName: "app_keystore.jks"
          encodedString: ${{ secrets.KEYSTORE }}

      - name: Build
        run: flutter build apk
        env:
          ANDROID_KEYSTORE_PATH: ${{ steps.write_file.outputs.filePath }}
          ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
          ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD }}
          ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}

      - name: Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1.3.2
        with:
          appId: ${{secrets.FIREBASE_APP_ID_STAGING}}
          token: ${{secrets.FIREBASE_TOKEN}}
          groups: testers
          file: /home/runner/work/{YOUR_REPO}/{YOUR_REPO}/build/app/outputs/flutter-apk/app-release.apk

As you can see, there are several steps that I'll describe here:

  1. You define your workflow to only work on main push
  2. You install Flutter thanks to an action (by default, the latest stable)
  3. You install the dependencies of your project
  4. You decode your Keystore from a base64 secret to a file named app_keystore.jks
  5. You build your apk with all the needed environment variables
  6. You distribute your app to Firebase Distribution to a group called testers

Define your secrets

As you can see in the previous YAML file, you need to define several secrets to properly work the script.

Go into the secret part of your GitHub repository, and add the following secrets:

  • KEYSTORE is your Keystore in base 64, this command will copy your key in the clipboard:
base64 app.keystore | pbcopy
  • ANDROID_KEYSTORE_ALIAS, ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD, ANDROID_KEYSTORE_PASSWORD are the alias and the password you have defined while creating your Keystore.
  • FIREBASE_TOKEN is a token you can get with the following command:
firebase login:ci
  • FIREBASE_APP_ID_STAGING is the id of your app; you can find it in the Firebase console in the settings

Also, don't forget to change YOUR_REPO to the name of your repo!

Once pushed to your main branch, you will have your Android app published to Firebase App Distribution!

Conclusion

As you can see, you can quickly set up a CI to deploy to Firebase App Distribution and get feedback quickly on your project as you go without going through store validation!

You can always subscribe to my newsletter below and follow me on Twitter to not miss my next article!