Firebase App Distribution with Codemagic

Oct 8, 2019

Automating the distribution of your Flutter Android apps from Codemagic has a few options: Google Play, Testmagic and others. Each has their pros and cons, but now there is a new and possibly better option: Firebase App Distribution. If you’d like to see the state of other app distribution options available via Codemagic, there is an overview in the article The Ultimate Guide to Beta Testing in 2019.

In this article, I’ll show you how to use Firebase App Distribution for Android apps via the Gradle plugin and a Codemagic custom script to distribute to testers in minutes. All with a user-friendly experience and no store approvals required.

To be clear, Codemagic does not yet (as at the time of writing this article) have ‘official support’ for publishing to Firebase App Distribution. But because Google provides an official Gradle plugin with Firebase App Distribution, the one-time setup is fairly straightforward and works very well with Codemagic.

What is Firebase App Distribution?

Firebase App Distribution is a new service that allows you to distribute pre-release Android and iOS apps to testers. It’s like Google Play internal/alpha/beta releases, but some key features are:

  • no app store reviews to complete (not even once)
  • tester management via groups, with import of tester emails
  • flexibility of versions where the developer can upload the same version multiple times and it’s up to the tester which they choose to install
  • public invites so anyone can join your test using the link
  • guided tester experience to walk them through the install
  • App Tester app for Android which is like the TestFlight app on iOS

Google acquired Fabric from Twitter in January 2017 and Firebase App Distribution is the evolution of the Crashlytics Beta testing feature. Firebase App Distribution was announced as Beta at the Firebase Summit in September 2019 and you can get a peek at it by looking at the Keynote at about the 27 minute mark.

You can learn a bit more about Firebase App Distribution on the product page and there is a nice short video titled Introducing Firebase App Distribution.

In the Firebase console you should see App Distribution under the Quality section:

How to set it up

This is a one-time setup based on Firebase App Distribution Gradle Plugin, Flutter and Firebase documentation. This guide will provide some more detail and hopefully help you skip common mistakes.

Firebase console

First, visit the Firebase console and select App Distribution. You will need to click the Get started button to provision your app to use App Distribution.

Adding Firebase to your Android project

Adding Firebase support to your project is not actually a hard requirement for using App Distribution. You can distribute apps without any Firebase SDKs or files. However, for this article I’ll assume that you have or will add Firebase support to your app. I highly recommend it for Flutter apps, if only for features like Analytics.

There is a lot of Firebase setup documentation around, both official and not official. The simplest, most up to date and best Flutter-specific documentation I’ve found is Add Firebase to your Flutter app on the official Firebase site. You should just go through the 4 steps and it’s a good idea to add Analytics to your Flutter app. As you follow these instructions, a couple of tips:

  • Check the latest versions of packages like flutter_analytics on pub.dev
  • In the /android/build.gradle file, there are more recent versions of the Google Services Plugin. I’d suggest (at the time of writing this) to use classpath'com.google.gms:google-services:4.3.0' which all the latest Firebase packages seem to have standardised on.
  • Once your app is set up for Firebase, App Distribution will use the google-services.json that you download when configuring your Firebase app. The gradle plugin will then automatically look for the Firebase App ID in the google-services.json. Otherwise you have to include the App ID in your build.gradle configuration, which overrides any App IDs in your google-services.json file.

If you need more help getting your Flutter project set up with Firebase, then there is also a Codemagic article Practical guide: Flutter + Firebase + Codemagic to give you a hand.

Set up your Android Project for App Distribution

In your Flutter project, you’ll have to update both of your build.gradle files:

  • /android/build.gradle — In the dependencies section within buildscript, add the firebase-appdistribution-gradle line:

    dependencies{
        classpath 'com.android.tools.build:gradle:3.4.1'
        classpath 'com.google.gms:google-services:4.3.0'
        classpath 'com.google.firebase:firebase-appdistribution-gradle:1.1.0'
    }
    

    Note: To check for the latest version, check the Google APIs for Android Release Notes.

  • /android/app/build.gradle — Add a new line after apply plugin:'com.android.application' for the appdistribution plugin:

    apply plugin: 'com.android.application'
    apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
    apply plugin: 'com.google.firebase.appdistribution'
    

Authenticate with Firebase using a service account

Before you can use the Firebase App Distribution Gradle plugin, you must first authenticate with your Firebase project. There are three ways to achieve this, but because we want to use Codemagic for CI/CD, you should choose the second option: Use Firebase service account credentials

Authenticating with a ‘service account’ allows you to flexibly use the plugin with Codemagic. Firebase runs on top of the Google Cloud Platform, so we need to create a ‘service account’ for our Firebase project in the Google Cloud Platform console. To do this:

  • Go to the Google Cloud Platform console and login with the same account you log in to the Firebase console with.

  • Select your Firebase project which should be listed. If it is not, search for it by name:

  • From the menu, select IAM & admin > Service accounts to see a list of the default service accounts already set up for your Firebase project.

  • Click on + CREATE SERVICE ACCOUNT and specify details for this new service account, something like shown below, then press CREATE.

  • In the next step, select the role of Firebase Quality Admin and click CONTINUE.

  • Click the + CREATE KEY button and choose JSON as the key type, then click CREATE.

  • This creates a private JSON key, so save the key file to a location accessible to your build environment. Be sure to keep this file somewhere safe, as it grants administrator access to your Firebase project. The file will be named something like yourappname-6e632def9ad4.json.

  • Temporarily make a copy of this JSON key file and put it in your Flutter project in the /android directory. We’ll be using this to test the setup later, although we don’t want this file to go into any public repositories because it is a private key that allows full admin access to your Firebase project.

  • Click DONE when finished and you should see your new service account appear in list of Service Accounts.

Configure App Distribution properties

In your /android/app/build.gradle file, configure App Distribution by adding at least one firebaseAppDistribution section. In the android section within buildTypes, add the firebaseAppDistribution section. All the options are explained in the table in the Configure your distribution properties section of the documentation.

For example, if you have an app and you want a Flutter release build to be used by testers:

buildTypes {
    release {
        // TODO: Add your own signing config for the release build.
        // Signing with the debug keys for now, so `flutter run --release` works.
        signingConfig signingConfigs.debug
        firebaseAppDistribution{
            serviceCredentialsFile="./yourappname-6e632def9ad4.json"
            releaseNotesFile="./release-notes.txt"
            testers="your-email-address@gmail.com"
        }
    }
}

Take special note of these properties:

  • serviceCredentialsFile is the private key JSON file we created previously for the service account. It should be located in the /android directory of your project. If you placed it somewhere else in your project, then adjust the path relative to your /android directory.

  • releaseNotesFile is a text file containing your release notes. I create a file in my project /android/release-notes.txt and every time I create a release, I replace its contents with what I want to tell my testers.

  • testers is list of email addresses for our testers. For now, just use your own email address so we can test the setup.

Distribute your app to testers

Here is where we will test the local setup of the Firebase App Distribution Gradle plugin and make sure it is publishing to Firebase App Distribution before we set it up in Codemagic.

  • First, do a release build of your Flutter app locally, to make sure it builds correctly. None of the changes we’ve made should stop a release build, but you may have made some typos so it’s best to check.

  • Open a terminal window and change into your /android subdirectory. From that /android subdirectory, run the command exactly as follows:

    ./gradlew assembleRelease appDistributionUploadRelease
    

    This command will do a full Gradle release build of your app for Android and then attempt to publish that build to Firebase App Distribution. If there are any issues with your project, they will tend to come out here and the publishing to Firebase App Distribution will fail.

    There will be lots of output and it will take a few minutes. But then if everything worked correctly, your Flutter app release build should have been set up in Firebase App Distribution. You should end up seeing something like this at the end in terminal:

    If you get the message Task :app:appDistributionUploadRelease FAILED, then check for typos in the firebaseAppDistribution section of the /android/app/build.gradle file and try again. You need to get this working locally before you set it up in Codemagic.

  • Log in to the Firebase console and select App Distribution from the menu. You should see your distribution which will look something like this:

    Note your version numbers will depend on what you had in your pubspec.yaml file of your Flutter app.

    You can expand this Distribution using the arrow icon at the right and you should see your email address as a listed tester on the Testers tab:

    Release notes from your release-notes.txt file in your project should also appear on the Release Notes tab:

  • You should have also received a Firebase App Distribution email inviting you to test the app. See below under Tester Experience for what these look like.

Now that the Firebase App Distribution Gradle plugin is working and publishing your app release, we can move onto automating the Codemagic setup.

Codemagic custom script

Codemagic setup is now very straightforward:

  • All the changes above need to be pushed up into your repository. So make sure you do a commit and push all these changes to your repository.

  • WARNING: The private key JSON file named something like yourappname-6e632def9ad4.json that grants full admin access to your Firebase project will get pushed up to your repository. If your repository is private, that might be fine for now.

    But if your repository is public, you might try this method to store the private key as a Codemagic environment variable. You can save it as a variable with the name $app-dist-service-account and then use it in /android/app/build.gradle file instead of the file name, so you can remove the private key JSON file from your project and the repo. Another approach is to use the method documented to keep Firebase credentials secure in Codemagic under Load Firebase configuration.

  • Log in to the Codemagic console and configure your app workflow. Click the ‘+’ button at the end to set up a Post-publish script. Add the following custom script and click Save.

    #!/usr/bin/env sh
    
    set -e   # exit on first failed command
    set -x   # print all executed commands to the log
    
    if [ "$FCI_BUILD_STEP_STATUS" == "success" ]
    then
      cd $FCI_BUILD_DIR/android
      ./gradlew appDistributionUploadRelease
    fi
    

    WARNING: We have removed the parameter assembleRelease from the gradlew command because we will run this script immediately after a Codemagic build of the release and this script only runs if the build was successful. All we need this custom script to do is find and upload the release to Firebase App Distribution, we don’t need to build the release again.

  • Update your app version which you may have set in the Codemagic build step as a build argument.

  • Start new build in Codemagic and check the results of the build under Post-publish script. If there are any errors they will be there. But having done a local test publishing to Firebase App Distribution earlier, we should have avoided any errors in Codemagic.

  • Once this build is complete, there should be a new distribution appearing in the Firebase console under App Distribution. This will be in addition to the one that was created when we tested locally so you should see two now. Your version numbers will be different depending on how and where you version your builds, but for example, my recent builds appear like this:

Congratulations!!!

You can now publish alpha and beta re-releases for Android with ease. But I bet you want to know all about the features of Firebase App Distribution now and what the testers see.

Managing testers

Now that this is working and automated, you probably want to better manage your app testers.

To set up a standard group of testers, select the Testers & Groups tab in the Firebase console under App Distribution. I usually create a group called Android Testers, to which I add all my testers with Android devices. You should then change your build.gradle file so we invite this group of testers, so replace:

testers="your-email-address@gmail.com"

with

groups="android-testers"

Note that the exact value for groups can be found in the Firebase console > App Distribution > Testers & Groups, then select your group and use the value next to the ‘?’ icon.

Alias for groups
Alias for groups

I’ve found managing the group and adding/removing/changing tester emails is most easily done in the Firebase console. By using a standard Android Testers group, you can set it once in your scripts and then just manage the tester emails in the Firebase console.

Tester experience

The tester experience involves two basic steps:

  1. Invite — The tester accepts the invite and the terms & conditions for testing this app. This is a one-time acceptance per app.
  2. Download the app — Download the latest build they have been assigned as testers for.

At this point, the tester gets a choice: continue with the web experience or install the App Tester app for Android. I would recommend installing the app, which is a few more steps but a better tester experience. But the tester can also just select the link to continue without the app and use the web experience.

Assuming the tester does not opt to install the App Tester app, they select Download latest distribution to install the app.

Take note of a few features here:

  • Testers can download and install any version of the app.
  • The Back to apps link at the top returns to a list of all apps the tester has been given access to. So if they have access to many apps, they will all be listed on this screen, but for example for just one app being tested:

If the tester opted to install the App Tester app, it works similarly with a list of apps for testing and a detailed list of each release:

Next steps

See the official Firebase App Distribution documentation for other features to explore, such as:

  • Invite links — a single link you can put on a website or Slack. No need to register the tester email, they self-register for testing, get an invite, accept it and then download the latest build.

  • In-app new build notifications (on the roadmap) — might help testers who install the App Tester app to get a notification when you have a new release for them to test.

Hopefully, this has helped get you started with another distribution option for your pre-release Flutter apps. Thanks for reading šŸ‘


This article is written by Mike Hughes.

Mike is a Product Manager, mobile developer using Flutter, GDG Melbourne Organiser and Leads the Flutter Melbourne Meetup group. He likes to build native mobile apps for Android & iOS using Flutter, to get into market super-fast with a full native experience.

You can contact him on Twitter at @mikehughestweet, or at LinkedIn

Codemagic CI for Flutter