Engineering

24 March, 2020

Android GitHub Actions Setup

We really liked GitHub Actions, it's a good alternative to other CI services so here is how to setup GitHub Actions in your Android project.

António Valente

Software Engineer

How to setup GitHub Actions for Android projects - Coletiv Blog

Here at Coletiv, when starting a new project, we always aim to deliver it following the highest standards of quality. Like so, continuous integration (CI) and continuous deployment (CD) are some of the first things we focus on before starting to code. That way we are sure that our code is always checked, tested and meets our quality standards before being deployed.

For Android specifically, we always used services like TravisCI or CircleCI for this task, but since we are heavy users of GitHub we couldn’t wait to experiment with GitHub Actions and check if it would be a better option for our projects. And guess what? It’s amazing!

Here is how we set up GitHub Actions on our Android projects.

Workflow Overview

We always have two types of workflows, one for testing and code checking and one for deploying. The first always runs on pull requests and the last only runs when the code is merged to master or develop.

Please note that we usually create multiple build variants for different environments. In this example, we’re running the commands for the staging build variant. You should change all the commands to your correct variant name or remove the staging word from them if you don’t need to use variants.

Testing Workflow

The purpose of this workflow is to run some lint checks and to run our tests. Here is the list of jobs that it performs:

  • Decode our Google services config file (if you’re not using Google services or Firebase you can remove this job).

  • Run Kotlin lint check.

  • Run Android lint check.

  • Run unit tests.

  • Run instrumented tests.

name: Testing Workflow # Step 1: Choose the branch or branches you want to run this workflow on: pull_request: branches: - develop jobs: testing: name: Lint Check and Testing runs-on: ubuntu-latest steps: - name: Clone Repo uses: actions/checkout@v1 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 # Step 2: Decode Google services configuration file - name: Decode google-services.json env: FIREBASE_CONFIG: ${{ secrets.FIREBASE_CONFIG }} run: echo $FIREBASE_CONFIG > app/google-services.json # Step 3: Check the code with ktlint, you can remove this job if you don't use ktlint - name: Run Kotlin Linter run: ./gradlew ktlintStagingDebugCheck # Step 3: Check the code with Android linter - name: Run Android Linter run: ./gradlew lintStagingDebug # Step 4: Yun your unit tests - name: Run Unit Tests run: ./gradlew testStagingDebugUnitTest # Step 4: Assemble debug apk to send to firebase test lab - name: Assemble Debug APK run: ./gradlew assembleStagingDebug # Step 4: Assemble debug test apk to send to firebase test lab - name: Assemble Debug Test APK run: ./gradlew assembleStagingDebugAndroidTest # Step 4: Run instrumented tests on firebase test lab - name: Run tests on Firebase Test Lab uses: asadmansr/Firebase-Test-Lab-Action@v1.0 with: arg-spec: '.github/test-lab-config-staging.yml:android-pixel-4' env: SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}

Let’s go step by step to explain everything.

  1. Tell GitHub when do you want to run this workflow. In this case, I’m saying that I want it to run on pull requests to the develop branch. You can tell it to run on any branch you like, just replace/add the name.

  2. Skipping a bit further, since we’re using the Google services, you need to go to the settings to add a new secret. Just create a new secret paste the content of your Google services JSON file there and choose a name. Our name for this secret is FIREBASE_CONFIG.

  3. We want to perform some checks to the code. For this, we’re using Ktlint and the built-in Android linter. To configure Ktlint check this and this. If you don’t need to run Kotlin checks delete the Kotlin linter job.

  4. Finally, we are creating jobs to run our tests. Running unit tests is pretty straightforward but running instrumented tests is really a pain because you need an emulator or real device to run them. You can go two ways here. Create a job to create and start an emulator on the CI machine (check this) or run them on Firebase Test Lab. We’ve chosen the last one and we’re using the awesome Firebase Test Lab Action. For more info on how to do this follow the guide.

android-pixel-4: type: instrumentation # Specify the path to the debug and test apks generated early app: app/build/outputs/apk/staging/debug/app-staging-debug.apk test: app/build/outputs/apk/androidTest/staging/debug/app-staging-debug-androidTest.apk device: - model: flame version: 29 locale: 'en' orientation: portrait

Deploy Workflow

Assuming that you have the develop and master branches protected and that you ran the testing workflow before doing a merge to these main branches, this workflow is very simple. It only needs to publish our app.

name: Deploy Workflow # Step 1: Choose the branch or branches you want to run this workflow on: push: branches: - develop jobs: deploy: name: Deploy runs-on: ubuntu-latest steps: - name: Clone Repo uses: actions/checkout@v1 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 # Step 2: Decode Google services configuration file - name: Decode google-services.json env: FIREBASE_CONFIG: ${{ secrets.FIREBASE_CONFIG }} run: echo $FIREBASE_CONFIG > app/google-services.json # Step 3: Decode the service account json key, needed on the next job - name: Decode service account key env: SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }} run: echo $SERVICE_ACCOUNT > app/service-account-key.json # Step 4: Publish the APK to the Play Store using the release keystore - name: Publish APK env: RELEASE_KEYSTORE_PASSWORD: ${{ secrests.RELEASE_KEYSTORE_PASSWORD }} RELEASE_KEY_ALIAS: ${{ secrests.RELEASE_KEY_ALIAS }} RELEASE_KEY_PASSWORD: ${{ secrests.RELEASE_KEY_PASSWORD }} run: ./gradlew publishStagingRelease

Let’s again go step by step to explain everything.

  1. Tell GitHub when to run this workflow. I’m saying that I want it to run on pushes to the develop branch.

  2. Like on the testing workflow we need the Google services JSON file so we’re decoding it before running any Gradle task.

  3. We also need to create a Google service account to be able to have publish access in the next job. Check this for more info. After creating the account you can download the JSON key and add it to the secrets like you’ve done before with the Google services JSON.

  4. Lastly, we are publishing the app using the Gradle Play Publisher plugin. You’ll need to add some configurations into your Android project to have this task available. For that please follow the instructions here. You also must add the release Keystore passwords and alias to the GitHub secrets as those are needed on this job and are sensitive data. Note that we usually have the Keystore file on our private repos, if you don’t want to have it there or you’re working on a public repo, you can also add it to your secrets and then decode it when running the workflow.

Final Thoughts

I really recommend that you give GitHub Actions a try in your next Android project. It’s easy to create and manage workflows as the syntax is very simple and understandable, the integration with other GitHub services is nice and having your CI builds in the same place of your repository is really a plus. Also, the community is amazing and the number of actions in the GitHub marketplace grows by the day.

Android

Software Development

GitHub

GitHub Actions

Continuous Integration

Continuous Deployment

Join our newsletter

Be part of our community and stay up to date with the latest blog posts.

Subscribe

Join our newsletter

Be part of our community and stay up to date with the latest blog posts.

Subscribe

You might also like...

Go back to blogNext
How to support a list of uploads as input with Absinthe GraphQL

Engineering

26 July, 2022

How to support a list of uploads as input with Absinthe GraphQL

As you might guess, in our day-to-day, we write GraphQL queries and mutations for Phoenix applications using Absinthe to be able to create, read, update and delete records.

Nuno Marinho

Software Engineer

Flutter Navigator 2.0 Made Easy with Auto Router - Coletiv Blog

Engineering

04 January, 2022

Flutter Navigator 2.0 Made Easy with Auto Router

If you are a Flutter developer you might have heard about or even tried the “new” way of navigating with Navigator 2.0, which might be one of the most controversial APIs I have seen.

António Valente

Software Engineer

Enabling PostgreSQL cron jobs on AWS RDS - Coletiv Blog

Engineering

04 November, 2021

Enabling PostgreSQL cron jobs on AWS RDS

A database cron job is a process for scheduling a procedure or command on your database to automate repetitive tasks. By default, cron jobs are disabled on PostgreSQL instances. Here is how you can enable them on Amazon Web Services (AWS) RDS console.

Nuno Marinho

Software Engineer

Go back to blogNext