Automate publishing your android app to Google Play Store with Fastlane and Github Actions
Tags: playstore, android, githubactions, fastlane
Published: 2023-04-20 07:33:30

Developers need fast and efficient way to deliver apps to the users, ensuring continuous integration and clear versioning of their apps.
Manual publishing of an app can be time-consuming and involves a lot of repetitive steps that could easily be automated, such as building and signing a new app file, logging in to the Google Play Console and uploading the file.
Therefore, the most efficient way to achieve this is automating the process of publishing the app to Google Play Store.

In this tutorial, I will show you how you can use [Fastlane](https://docs.fastlane.tools/) and [Gihtub Actions](https://docs.github.com/en/actions) to automatically upload an android app bundle (.aab) to Google Play Store.

## Prerequisites

Before we proceed with the tutorial, you will need to have done the following:

[1. Create a Google Play Developer Account](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en)

[2. Setup an app in your account](https://support.google.com/googleplay/android-developer/answer/9859152?hl=en)

[3. Enable Google Play Android Developer API](https://support.google.com/googleapi/answer/6158841?hl=en)

[4. Enroll on Play App Signing](https://support.google.com/googleplay/android-developer/answer/9842756?hl=en): if you are not sure how to enroll, check out this super concise tutorial on [jmango360](https://support.jmango360.com/portal/en/kb/articles/enroll-in-app-signing-by-google-play)

[5. Configure your app to use the correct upload key for signing the app](https://reactnative.dev/docs/signed-apk-android#setting-up-gradle-variables): it must be the one used to enroll for Play App Signing and for the purposes of this tutorial it will be called `myKeystore.keystore`

## 1. Create a service account and JSON key

To automate the process of publishing your app to Google Play Store you will have to provide a JSON key, which will be used for authentication against Google Play Developer API.
In order to obtain this key, you have to setup a service account first.

### Create a new service account

Step 1: Login to **Google Cloud Console**

Step 2: Navigate to **IAM & Admin** and select **Service Accounts**

Step 3: Create a new service account and assign the role of **Basic Editor** to it.

### Generate a new json key

Step 4: Navigate to the service account you have just created, click on **create new key** and select type **JSON**.

Download the key and store it securely. For the purposes of this tutorial rename the file to `service-account.json`.

### Invite the service account user to the app project

Step 5: Login to **Google Play Console** and navigate to **Setup** -> **API access**

Step 6: Find the service account name (email) and grant **admin** access to it. If you want to keep the permissions to the minimum required, make sure that you have selected everything under the release section.

Note: Be aware that granting access to the service account can only be performed by the **owner of the google developer account**.

## 2. Setting up Fastlane

Step 1: Make sure that you have installed Ruby on your machine:

```shell
    ruby -v
```

Step 2: Install fastlane:

```shell
    gem install fastlane -NV
```

Step 3: At the root of the project (i.e. `android/`) run the following command to initialise fastlane:

```shell
    fastlane init
```

This will prompt you to enter the name of the package, e.g. "io.appname.app".
You can press enter to skip the rest of the questions, as they can be configured later.
When asked "Download existing metadata and setup metadata management?" respond with no (i.e. `n`).

After the command has been executed you will notice that a new folder `fastlane` has been created.
Inside this folder there will be two files - `Appfile` and `Fastfile`.
Place the `service-account.json` in the `fastlane/` folder, but **do NOT commit it to github**.

Step 4: In the `fastlane/Appfile` define the path to the service account json key (relative to where the fastlane actions will be called) and the package name.

Assuming that the fastlane actions will be called at the root of the project, the `Appfile` content looks like this:

```shell
    json_key_file("fastlane/service-account.json")
    package_name("io.appname.app")
```

Important: When you use github actions make sure to restore the json key in the correct directory (i.e. `fastlane/`).

Step 5: The `fastlane/Fastfile` is where all methods (a.k.a lanes) must be defined.

Let's take a look at the following `Fastfile`.

There are two lanes (methods), the first of which is `:internal`. It uses the `gradle` action to build an app bundle (.aab) and the `upload_to_play_store` action to upload the bundle to the internal track on the play store (the other track options are 'alpha', 'beta' and 'production').
To find out more about the google play tracks click [here](https://developers.google.com/android-publisher/tracks).

The second lane is `:production` and uses the same actions to build and publish the bundle to the production track on Google Play.

```rb
    default_platform(:android)

        platform :android do

            # LANE 1
            desc "Publish a new version to the Google Play (INTERNAL)"
            lane :internal do

                # Generate AAB file
                gradle(
                task: "bundle",
                build_type: "Release"
                )

                # Upload the AAB to play store (internal track)
                upload_to_play_store(track: 'internal')
            end

            # LANE 2
            desc "Publish a new version to the Google Play (PROD)"
            lane :production do

                # Generate AAB file
                gradle(
                task: "bundle",
                build_type: "Release"
                )

                # Upload the AAB to play store (production track)
                upload_to_play_store(track: 'production')
            end
        end

```

If you want to make sure everything works as expected before you publish your app, you could pass the `validate_only: true` argument to the `upload_to_play_store` action.
It will only verify that everything is correct without actually publishing the app on the selected track.

```rb
    # Validate upload the AAB to play store (production track)
    upload_to_play_store(track: 'production', validate_only: true)
```

Note: You can find all available arguments for `upload_to_play_store` [here](https://docs.fastlane.tools/actions/upload_to_play_store/)

If you want to run the `:production` lane locally, execute the following command in your terminal (note: make sure you are working in the root dir):

```shell
    bundle exec fastlane production
```

## 3. Create a workflow with Github Actions

### Create new repository secrets for the JSON key and upload key (`myKeystore.keystore`)

Both the upload key and the service account json key contain sensitive information which should be stored securely and hence, should not be pushed to the github repository.
In order to be able to access them from within the workflow, you have to obtain them from the repository secrets. To achieve this, let's first ecrypt/encode them:

Step 1: Encrypt the .keystore file, in the terminal run the following command:

```shell
    gpg -c -armor myKeystore.keystore
```

This command will prompt you to enter a passphrase. Important: Make note of the passphrase.

After successful exection you will be able to see a `myKeystore.keystore.asc` file in the current directory.

Step 2: Create a new repository secret (ENCRYPTED_KEYSTORE), containing the content of `myKeystore.keystore.asc`

Step 3: Create a new repository secret (ENCRYPTED_KEYSTORE_PASSPHRASE), containing the passphrase, used to encrypt the keystore (ref. Step 1)

Step 4: Encode the JSON key

```shell
    base64 -it service-account.json -o encoded.base64.txt
```

Step 5: Create new repository secret (SERVICE_ACCOUNT_JSON) and place the content of the `encoded.base64.txt`

### Create a new github workflow

Now, that Fastlane and the secrets have been setup, let's create the workflow `.github/workflows/publish_play_store.yml`, containing the following:

```yml
name: Publish to Play Store ( Internal track )

on:
  workflow_disptach:

jobs:
  upload-play-store-internal:
    name: Upload app to Play Store (Internal track)
    runs-on: ubuntu-latest

    steps:
      - name: Check out repository
        uses: actions/checkout@v3

      - name: Setup ruby
        uses: actions/setup-ruby@v1
        with:
          ruby-version: "3.x"

      - name: Setup fastlane
        run: |
          cd android
          bundle install
          cd ..

      - name: Restore json key # make sure that you restore the key in the correct directory (ref. fastlane/Appfile)
        run: |
          cd android/fastlane
          echo "${{ secrets.SERVICE_ACCOUNT_JSON }}" | base64 --decode > service-account.json
          cd ../..

      - name: Restore keystore # make sure that you restore the key in the correct directory (same as app/gradle.properties)
        run: |
          cd android/app
          echo "${{ secrets.ENCRYPTED_KEYSTORE }}" > myKeystore.keystore.asc
          gpg -d --passphrase ${{ secrets.ENCRYPTED_KEYSTORE_PASSPHRASE }} --batch myKeystore.keystore.asc > myKeystore.keystore
          cd ../..

      - name: Set up JDK environment
        uses: actions/setup-java@v3
        with:
          distribution: "zulu"
          java-version: 11

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Make Gradlew Executable
        run: cd android && chmod +x ./gradlew

      - name: Upload app to Play Store (Internal track)
        run: |
          cd android
          bundle exec fastlane internal
```

Congratulations, you have automated your app publishing process.
All you have to do is run the workflow and your app will be available to testers on the internal track. To publish the app on the production track instead, simply switch the lane in the final step to poduction and you are good to go.

### Conclusion 
Automating your app deployment can save you hours of building, testing, and releasing
your app on a regular basis. In this tutorial I have walked you through the steps
of automating the process of building and publishing an android app to Google Play
Store. If you are interested in reading other tutorials related to play store automation
with Gihtub Actions, I recommend these amazing articles by Tomer Ben Rachel on [freecodecamp.org](https://www.freecodecamp.org/news/use-github-actions-to-automate-android-development/)
and by Shreyas Patil on [medium.com](https://medium.com/scalereal/automate-publishing-app-to-the-google-play-store-with-github-actions-fastlane-ac9104712486)