Using Github Actions to publish your Flutter APP to Firebase App Distribution
Tags: flutter, firebase, github, tutorial
Published: 2023-01-05 04:04:15

## Hey, everyone! 👋🏻

I want to start talking about my decision for this year, which is to start to write more tech articles to help people, increase my knowledges (cuz I need to study either ^^) and also improve my english writting skills. So, this will be the beggining of this journey and I hope you all could enjoy it :)

## Summary

[1. Why am I writting this article?](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s1)
[2. Firebase App Distribution](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s2)
[3. The manually way](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s3)
[4. The GitHub workflows way](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s4) (main topic)
[5. Final workflow yaml file result](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s5)
[6. Testing it!](https://dev.to/feliperfdev/using-github-actions-to-publish-your-flutter-app-to-firebase-app-distribution-1dcf#s6)

## 1. Why am I writting this article? <a name='s1'>

Few months ago I started to develop a Flutter app side-project, which is not available yet, but I intend to publish it on app stores when I feel that it is ready for MVP release.
On this project, I'm using Firebase database to store the app data, authentication, files storaging and some other features. BUT we have one that is the main topic of this article: **Firebase App Distribution**.

## 2. Firebase App Distribution <a name='s2'>

Firebase has it own functionality whose job is literally distribute your app to an user (or a group of users).
When we're talking about Flutter apps, we're also talking about downloading this apps at our mobile devices (in case mobile apps, I'm not going to talk about Flutter Web at this article). Maybe you or your team wanna test it or show it for the team manager or team leader, whatever.
This is the "nice" but rough way to do it. Uploading your app file to Firebase App Distribution.

## 3. The **manually** way <a name='s3'>

First of all, of course, you'll need to generate a build of your Flutter app.

```
flutter build apk
```

or

```
flutter build aab
```

When you get into your Firebase project console, you have in the left side a shortcuts list, and you will probably see an option named 'App Distribution'. Click on it.


![Shortcuts](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ma6dqeb0owmy62ek02c8.png)

You'll see a big dashed blue box asking you to upload your app APK or AAB file.


![Dashed blue box](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dawoa712yid86sitpcrt.png)

After that, it will appear a card with a text field to put the tester e-mail or the name of a tester group (which you can create by clicking at third top navigation bar).


![Send to testers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ylwdxi1ziv1yk5pkxzb.png)

Then, you'll just need to press 'Next' and 'Send to testers'.

Well done! Now, your app is on the devices of all the testers you sent it.
But... Doing this EVERY time sounds like a waste of time. Isn't? Maybe. Maybe not.

But we can do it better. Follow me to the next topic!

## 4. The **GitHub Actions** way <a name='s4'>

Now, in the main topic of this article, I'll show you how automate this process of uploading your app to Firebase App Distribution and send it to testers.
In the end of this topic, you'll know how to do this process just by pushing or opening a pull request on a specific Git branch of your project.

In your project, create a path named `.github/workflows`, just like that:


![Folders path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/52wznmlwrunibcjg95d1.png)

Inside of it, create a `.yaml` file with the name of your workflow. I named mine as 'firebase_workflow.yaml'.

Let's beggin by giving a name to the workflow.

```yaml
name: Firebase APP Workflow
```

Then, we will need to determine when this workflow will be triggered. Pushing to a branch? Creating a pull request to a branch?

Exemple of how it should looks like the yaml file until here:

```yaml
name: Firebase APP workflow

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main
```

We need to put jobs on our workflow file. Above we have an exemple of setting that is very important for the whole workflow operation.

I created a key named `firebase_distribution` and gave it the name "Firebase App Distribution". Then, I setted the virtual machine which would it runs on. [You can read more about this here](https://github.com/actions/runner-images).

```yaml
jobs:
  firebase_distribution:
    name: Firebase App Distribution
    runs-on: ubuntu-latest ## virtual machine
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v1
        with:
          java-version: "12.x"
```

Then, we have two important initial steps to define. The [first one](https://github.com/actions/checkout) is an official GitHub Action used to check-out a repository so a workflow can access it. The [second one](https://github.com/actions/setup-java) it's pretty more complex but, briefly, downloads and set up a requested version of Java.

Continuing the steps:

Give a name to this step, now we gonna make our workflow decode the most important file which makes Firebase work on our project: the `google-services.json`.

```yaml
      - name: Decode google-services.json
        env: 
            GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo "$GOOGLE_SERVICES_JSON" > android/app/google-services.json
```
Inside *env* key we put another key called *GOOGLE_SERVICES_JSON*. But, for now, I'll need to explain what is this "secrets.GOOGLE_SERVICES_JSON" here.

For this, open your Github project repository and get into settings page.

On the left side options, look for the security session and click on "Secrets" > "Actions".


![options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfmjovwlx0u9d7urnplq.png)

We need to create 3 secret keys. Each one for:
- Firebase App ID
- Firebase Token
- Google Services Json

Name them by your preference.

The Firebase App ID can be found by following this short click steps on your Firebase project console:

![Firebase App ID](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63paxi9fn335p562z7tn.png)

We just need to copy and paste it on our secret key.

Firebase token can be obtained by running a few commands on your machine.

At first, we'll need to install [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) and run the following command:

```
npm install -g firebase-tools
```

Then, run this second command:

```
firebase login:ci
```

After that, the token will be shown by your CLI.

For the last key, we just need to open the `google-services.json` on our project in path *"android/app/google-services.json"*, copy the whole content inside and paste it on the respective secret key in your Github project repository.

Now, we can get back into our workflow and understand what will happen from now:

```yaml
      - name: Decode google-services.json
        env: 
            GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo "$GOOGLE_SERVICES_JSON" > android/app/google-services.json
```

Basically, using ***secrets.KEY_NAME*** allows us to access our project secret keys.

We're accessing the secret key named `GOOGLE_SERVICES_JSON` and running a command on it.

Now, we can continue writting our workflow:

```yaml
      - uses: subosito/flutter-action@v1
        with:
          channel: "stable"
```

subosito/flutter-actions@v1 is just a Flutter enviroment running on our workflow. So, now we have 'access' to Flutter enviroment, we can choose a Flutter channel to use. [Read about this action here](https://github.com/marketplace/actions/flutter-action).

From now, we will run Flutter commands inside our workflow:

```yaml
      - run: flutter pub get
      - run: flutter build apk
      - uses: actions/upload-artifact@v1
        with:
          name: release-apk
          path: build/app/outputs/apk/release/app-release.apk
```

Notice that already known commands like `flutter pub get` and `flutter build apk` now it shows up on our workflow. But, to upload the generated app file (artifact), we'll need to use the action [upload-artifact@v1](https://github.com/actions/upload-artifact) and parse the build path which it will be storing the app file.

To finally finish this (I swear), we complete our workflow with a Firebase action that will have the responsability to upload the app to Firebase App Distribution. Read about [wzieba/Firebase-Distribution-Github-Action](https://github.com/wzieba/Firebase-Distribution-Github-Action). **This action uploads your artifacts with .apk, .aab and .ipa (this last one for iOS) extensions to Firebase App Distribution.**

```yaml
      - name: upload artifact to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
            appId: ${{secrets.FIREBASE_APP_ID}}
            token: ${{secrets.FIREBASE_TOKEN}}
            groups: testers
            file: build/app/outputs/flutter-apk/app.apk
```

We'll need to parse the remeaning secret keys, the tester group name (which you created at your Firebase project console) and the file path. In Flutter, by default, it is stored at `build/app/outputs/apk/release/app-release.apk`.

That's it! Our workflow process file is done!

## 5. Final workflow yaml file result <a name='s5'>

This is how your workflow file should looks like:

```yaml
name: Firebase APP workflow

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

jobs:
  firebase_app:
    name: Run Firebase Workflow
    runs-on: ubuntu-latest ## virtual machine
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v1
        with:
          java-version: "12.x"
      
      - name: Decode google-services.json
        env: 
            GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo "$GOOGLE_SERVICES_JSON" > android/app/google-services.json

      - uses: subosito/flutter-action@v1
        with:
          channel: "stable"
      - run: flutter pub get
      - run: flutter build apk
      - uses: actions/upload-artifact@v1
        with:
          name: release-apk
          path: build/app/outputs/apk/release/app-release.apk
      - name: Upload to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
            appId: ${{secrets.FIREBASE_APP_ID}}
            token: ${{secrets.FIREBASE_TOKEN}}
            groups: testers
            file: build/app/outputs/flutter-apk/app.apk

```

## 6. Testing it! <a name='s6'>

Now, we just need to push our project to github's project branch which we had chosen or merge pull request (it depends on what did you choose to do) to trigger the workflow.

After that, you can see the process working by clicking at "Actions" tab in your project repository.


![Actions tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nr713hdhm42rauk68yxd.png)

This is how it should your workflow alert looks like:

![Workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iuflfpfe54r0w7wqthbp.png)

---

## That's it!

Thanks A LOT for reading until here! I hope this article may help you create github actions workflows to upload your app to Firebase APP Distribution.