Using Gitlab CI to Build Android Project

This post is brought to you by TestFairy, a mobile testing platform that helps companies streamline their mobile development process and fix bugs faster.
See how TestFairy can help you at testfairy.com

Last year Gitlab added a CI feature that is really useful for deployment.  This free feature can also be used by Android developers to automate their APK builds, which is a  major benefit compared to other premium build or CI systems set up on the server. Gitlab CI is limited to 2000 minutes per month for private projects and unlimited for public projects. In this post, we’ll be learning how to use Gitlab CI to build an unsigned APK.

Setup

Setup Git inside your existing project / new project and then, create a new project in Gitlab and point the remote to itt. Next, we create a new file inside our root Android project with .gitlab-ci.yml as the filename.

This file contains configuration for Gitlab CI. Documentation can be found here that will show you what this file should contain. Next, for our Android project, it is possible to create a configuration that will install and set up everything to run the Android SDK, but this is not the best practice. Instead, we will use a docker image from Jangrewe GitHub which has everything set up & configured inside. paste these lines inside .gitlab-ci.yml:

image: jangrewe/gitlab-ci-android

stages:
- build

before_script:
- export GRADLE_USER_HOME=$(pwd)/.gradle
- chmod +x ./gradlew

cache:
  key: ${CI_PROJECT_ID}
  paths:
  - .gradle/

build:
  stage: build
  script:
  - ./gradlew assembleDebug
  artifacts:
    paths:
    - app/build/outputs/

By default a pipeline in Gitlab CI runs  3 stages: build, test and deploy. We will only use the build stage here, other stages will be omitted if they are not defined in the config.

Next, we will activate a Shared Runner by opening Gitlab Setting → CI/CD and clicking Enable Shared Runner if it hasn’t already been enabled by default. A Runner is a Gitlab process that runs the CI, and a Shared Runner is a type of Runner that’ is provided by Gitlab, so that we don’t need to set up anything on our computer or server.

Activate CI

Next, we commit and push our project to Gitlab. Then we open Gitlab and click on CI/CD → Pipelines, and it will show any pipeline that is currently running as well as past pipelines that have been run previously.

On the Jobs submenu, it will display current job details, so if you have 3 stages, it will show the progress of each stage.

By pressing where it says running in the status column, the page will switch to Terminal display to show what is happening behind the scenes.

After the build has finished, a passed indicator will be shown in the status column, if you click on it, there will be 2 new buttons on the right under Job artifacts: Download and Browse. Use these buttons to download your build (zip) or browse what’s contained inside your build. To download this build, you can also use the button on the right on the Pipelines/Jobs menu.

Our example above can be accessed in this repository. You can download the final build from that repository here.

Note :

Please remember that this is an unsigned APK. It is highly not recommended to upload your keystore to the repository so you can make a signed APK. To make a signed APK locally please run these commands locally :

  • zipalign the unsigned apk:
zipalign -v -p 4 input-unsigned.apk input-aligned.apk
  • Sign apk using apksigner:
apksigner sign --ks keystore.jks --out output-release.apk input-aligned.apk
  • Verify that output-release.apk has been appropriately signed:
apksigner verify my-app-release.apk

Upload APK to TestFairy

If you already have a TestFairy account, uploading the APK to TestFairy is very simple. First, find your TestFairy API Key inside Account Preferences and then copy the key and paste it into the Gitlab CI Secret Variable.

Then, add a new job inside the .gitlab-ci.yml configuration above.

image: jangrewe/gitlab-ci-android

stages:
- build
- deploy

before_script:
  ...

cache:
  ...

build:
  ...

deploy:
  stage: deploy
  only:
    - master
  script:
    - |
      curl \
        -A "GitLab CI" \
        -F api_key="${TESTFAIRY_API_KEY}" \
        -F comment="GitLab Pipeline build ${CI_COMMIT_SHA}" \
        -F file=@android.apk \
        https://upload.testfairy.com/api/upload/

Replace -F file=@android.apk argument with a path to your APK.

*If you want to upload the debug APK from the build step, change the value in deploy into:

deploy:
  stage: deploy
  only:
    - master
  script:
    - |
      curl \
        -A "GitLab CI" \
        -F api_key="${TESTFAIRY_API_KEY}" \
        -F comment="GitLab Pipeline build ${CI_COMMIT_SHA}" \
        -F file=app/build/outputs/apk/debug/app-debug.apk \
        https://upload.testfairy.com/api/upload/
  dependencies:
    - build

The dependencies keyword means that the deploy step requires the artifact from the build stage. This command will pass the artifact and auto extract the content. Then we can change the file argument path into app-debug.apk path from the extracted artifact.