Setup your CI/CD Pipeline with Fastlane and Github actions for Android apps

Milan Vadhel
Mindful Engineering
9 min readJul 6, 2022

In the previous article, we have covered Fastlane and in this article, we will cover it in a more advanced way with Github actions to set up your CICD pipelines.

Image by Mindinventory

Developing android apps is amazing but while creating the build, uploading it to the Play store or Firebase app distribution is time taking job. Sometimes small bugs can be fixed in less time but again creating the build and supplying it to the beta testers or QA may take more time because Gradle takes a noticeable time to create the build.

Also, every time whenever any new feature is completed, you need to create the build again and pass it to the tester. It is annoying indeed. We need a solution that deploys our build to Firebase app distribution or Play Store automatically without doing manually. This is where CICD shines.

In the market, there are many CICD tools available that can be integrated with the version control systems (Github, Gitlab, etc.). We will use Github here which provides Github actions using which we can make something like whenever any code merges to the main branch it will automatically trigger the build creation process, upload it to firebase app distribution, and also drop a message in slack to notify the client or testers that a new build is available, and ready to test.

In this article, we will cover everything from creating the GitHub actions to notifying in slack.

First, let’s know the basics about CICD and Github Actions.

Image by https://www.mabl.com/blog/what-is-cicd

What is CICD?

While developing the software we can not keep a client waiting until the whole software is developed. Instead of that, basically what we can do is develop one feature or module of the software and deliver it to clients to let them know that the development is in progress.

We deliver the software in feature-by-feature mode. But every time creating a small copy of the software and delivering it to the client manually is not a good practice. Ideally, developers only need to focus on development (feature integration) and delivering or deployment part should automatically be done using CICD aka Continuous integration and continuous delivery/deployment.

Image by https://www.giuseppemaccario.com/continuous-deployment-with-github-actions-on-a-shared-server/

What is Github Action?

Before going with Github Action, let’s look over some basic terminologies.

Event: Event means something that has occurred. Ex. push, merge, PR, and Issue creation are called events.

Workflows (Event -> Steps -> Runners -> Steps -> Actions ): Set of events or steps of work that we want to perform when an event has occurred right in your repository.

Runner: Runner is like an OS on your local system. The runner is available on the Github server which will perform tasks for us on a specified OS.

Github actions mean how we trigger our workflow when an event occurs right in your Github repository.

Automate, customize, and execute your software development workflows right in your repository with GitHub Actions. You can discover, create, and share actions to perform any job you’d like, including CI/CD, and combine actions in a completely customized workflow.

Now let’s write our GitHub action step by step to trigger the build creation when any feature branch gets merged into the master branch, upload it to the Firebase App Distribution, and send the message in slack.

(1) Create the .github -> workflows folder in your project and create the .yml file inside that.

A simple format of the .yml file will be as per below :

(2) Specify the workflow name, event name, and branch name in which the feature branch will be merged as per the below code snippet.

name: Create and Upload Build on Firebase.

on:
push:
branches: [ main ]

Here our event type will remain push as there is not any merge event. So whenever any feature branch will be merged into the main branch, this workflow will execute.

(3) Now write down the code as per mentioned below.

jobs:
CI-Upload-APK:
name: Production build uploading
runs-on: ubuntu-latest

jobs: It means a set of steps we will write later in code to perform certain operations. You can write multiple jobs here. Ex: CI-Upload-Stage-APK, CI-Upload-Prod-APK.

CI-Upload-APK: It is our job name and you can write anything you want.

name: You can write the description regarding whatever task the job will perform.

runs-on: Here Github has hosted some of the systems on their server and what we gonna do is to tell Github that I want to perform this workflow on a specific system(Ubuntu, Windows, or Mac OS). You can choose your runner from here.

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build, upload it to firebase and send the message in slack. It will save significant amount of time and you can focus on the development.

Before going to write the steps we need to store all required keys as the environment variables on GitHub runner to use in our script and Fastfile.

Why do we need to store it as environment variables?

Because as android developers we should take care of security also. We should not store our .jks file, private API keys, or Google service account JSON file to our VCS. To provide the values to the environment variables, we will add all required values in Github secrets.

In the setting section of your GitHub repository, you will find the Secrets as per the below image.

Image by https://gluonhq.com/use-github-actions-to-automate-your-gluon-build-and-release-cycle/

(4) The steps that we are going to perform in our job :

  • Checkout Repository tells GitHub to check out your code repository on Github runner.
  • Setup JDK on Github runner.
  • Setup Ruby and Install bundler on Github runner which is required for Fastlane. As per the previous article, we will drive our Fastlane’s lane here to upload the build on Firebase App Distribution.
  • Install the Firebase App Distribution plugin on Github runner.
  • Generate the Google service account JSON file on the Github runner and provide the path of that generated JSON file in Fastfile while fetching the latest release version from Firebase App Distribution.
  • Upgrade the versionCode and versionName of our build which is going to upload on Firebase App Distribution(We will write one lane in Fastfile to fetch the latest build uploaded version from Firebase App Distribution and increment versionCode and versionName into our build.gradle file).
  • Generate the .jks file to sign our build which will be given as a path in our Fastfile’s lane to upload the build to firebase.
  • Upload .apk file to Firebase App Distribution
  • Slack notification for success or failure based on the build creation and uploading.

The Github community has already built many GitHub actions to make it easy to write our action script. We will use some of them here.

(5) Checkout Repository

steps:
- name: Checkout repository
uses: actions/checkout@v2

(6) Setup JDK

- name: Setup JDK
uses: actions/setup-java@v1
with:
java-version: 11

(7) Setup Ruby

- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: '2.6'

(8) Install the Bundler & Fastlane

- name: Install bundler & Fastlane
run: |
gem install bundler:2.2.27
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3

(9) Install the Firebase App Distribution plugin

- name: Install Firebase app distribution plugin
run: fastlane add_plugin firebase_app_distribution

(10) Generate the Google service account JSON file

- name: Generate private-decoded-key.json file
run: echo ${{secrets.PRIVATE_SERVICE_ACCOUNT_KEY}} | base64 -d > /home/runner/work/FastlaneSampleProject/FastlaneSampleProject/private-decoded-key.json

As above said that we should not store secret stuff in VCS. For API keys we can provide it via Github secrets but we can not store the files like .json or .jks in Github secrets. So we need to store the encoded strings in GitHub secrets and decode them while using. To encode & decode we will use base64 here.

Note: Whatever generated file path we are giving here is of our runner. (Ex : /home/runner/work/YourRepositoryName/YourProjectName/filename.json)

Run the below command to generate encoded string of your .jks/.json file in your terminal:

base64 Your-File-path -w 0 > your-file-name.txt

It will create an your-file-name.txt file with encoded string.

Just copy that encoded string and past it in GitHub secrets with a specific key name.

(11) Upgrade the versionCode and versionName of our build

- name: Upgrade build version
run: bundle exec fastlane getLatestProdVersionAndUpdate

(12) Generate the .jks file

- name: Generate .jks file
run: echo ${{secrets.ANDROID_SIGNING_KEY}} | base64 -d > /home/runner/work/driver-android/driver-android/app/release-keystore.jks

(13) Upload .apk file to Firebase App Distribution

# Step 8 Run the fastlane command to upload the build
- name: Upload .apk to Firebase
run: bundle exec fastlane uploadApkToFirebase

(14) Slack notification

- name: Slack notification for success
if: ${{job.status == 'success'}}
run: bundle exec fastlane sendBuildUploadSuccessMessage
- name: Slack notification for failed
if: ${{job.status == 'failure'}}
run: bundle exec fastlane sendBuildUploadFailMessage

Finally, our GitHub action script will look like the below code snippet.

Here whenever any child branch will merge in the fastlane-with-github-action branch then this action will trigger.

As we said we have written lanes to fetch the latest build version from Firebase App Distribution and slack notification.

Note: You can find your Slack webhook URL from your slack configuration.

Well, our GitHub action script will only run when any child branch merges in the specified branch. But suppose we want to trigger the build from the branch which is not specified in our action script then? We can do that by replacing our event name with the below code and that’s it. Now anyone can run the workflow manually directly from GitHub from any branch. Even clients can also do that if they want a fresh build.

on:
workflow_dispatch:

Just navigate to the Actions section in your Repository and run the workflow manually. Also, you can check the status of your workflow from there.

You can check the workflow we have triggered to upload the build on Firebase App Distribution with the below images.

How does GitHub run our code and trigger the build from where? And How it works?

Github has its own server with some specific systems. Whenever any workflow is triggered, the Github will look for an idle virtual OS and perform specified steps from the action script.

Does GitHub provide free service?

No, they charge the money for the service as per the system requirement. It calculates money based on how many minutes your workflow takes to run. You can read more about billing from here.

How to save money while using GitHub actions?

We can use our self-hosted runner to run the workflow. Explore more from here.

Well, a lot more we have covered in this article and I hope it will helpful to you. You can find the source here.

Please share this article if you like it and don’t forget to give a clap. Feel free to write a comment if you have any queries.

Keep Learning — Keep Growing — Keep Achieving

--

--