Build and test Android with Gitlab Continuous Integration

In this article I’ll try to explain how we, at Oddbit, are developing for Android with Continuous Integration to build, test and package deliverables for our clients.

Dennis Alund
oddbit

--

At the end of the article, you will find a complete Gitlab CI configuration script that is ready to be used, straight out of the box.

Gitlab

Gitlab is definitely not getting a proportional amount of credits that they deserve. At least not in my circles and part of the world. But I do my fair share of praising whenever I get the chance.

GitHub is great for the open source community. But Gitlab is a one-stop-shop solution for a developer team like ours. I’ve written a few articles specifically on Gitlab CI in the past, because it’s one of the things I love the best with the platform.

In this article’s example gists, you can see that I’ve configured the script with “anchors” that allow us to re-use job specs in a modular DNRY way. Read more about it on Gitlab documentation if you are not sure about it yet.

Step 1: Build

In order to build Android on Gitlab CI, we’ll need to setup the environment and download and install a few packages first. Roll up your sleeves, we’ll get our hands dirty!

Let’s break this down into digestible pieces.

Start with downloading the latest version of SDK Tools, and in order to do that, we’ll have to explicitly define the version that we want to use. For my convenience, I have put the ANDROID_SDK_TOOLS version in a build environment variable, which was set to “3859397”, the latest build at the time of writing. (note to the helpful reader: I’d be happy to know if there’s a symlink to the “latest” package to download instead of having to specify the build version)

https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip

I’ve chosen to extract the package into a folder named “.android” within the project structure since I want to keep the files as artifacts to subsequent jobs. The artifacts are configured to expire after 4 hours, which is more than enough time to execute long running tests. Because that’s all we’ll need it for. There is a separate step at the end that will package the client deliverables.

Once you’ve extracted the package we can utilize the sdkmanager CLI tool to do all the same operations that Android Studio smoothly does for you. In one of the first lines, we extracted the build target SDK configuration from app/build.gradle, we’ll use it to install the platform tools and target SDK that we want to compile or app against.

$ sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"

That’s about it. Commit, push, wait… or continue with the subsequent steps.

Step 2: Test

In this example, the test step is only running unit testing. But as we’ll see in my next article “Deploying to Firebase Test Lab with Gitlab CI”, we can execute CI jobs in parallel before finally packaging the deliverables if all tests passed.

As you can see, there’s not much to explain in this step. The downloaded libraries and generated binaries from the build step are made available thanks to the artifacts configuration.

Step 3: Package

Finally, if everything has gone well up until here, then we’ll create a nice little zip file that we can download and send to our project manager, client or whomever that you would like to show off your latest build to.

As a simple example, this script is doing two things:

  1. Renaming the APK with the name of the app (replace “NameOfTheApp” to whatever your app is called) and adding the version information to the file name.
  2. Creating a simple text file with some additional information about the build: date, commit, pipeline id, etc.

The resulting package is stored for a certain amount of time, which you can configure to your own liking (optionally, you can even remove the expiry time altogether if that’s the sort of thing that you’re in to).

I’ve chosen to remove my “development” builds after 3 days, since it’s a busy branch that is sure to contain the latest development build even on Monday morning.

The release branch is keeping its deliverables for a longer period of time that spans over more than one sprint, therefore guaranteeing that we’re having the latest production app ready to be downloaded from the repository at any time.

If your project development is in vacuum for some time, you can choose to increase (or remove) the production expiry time. Or otherwise configure a scheduled build every few weeks on the master branch. Just to make sure everything is still ok :-)

The full configuration

Here’s the full configuration, ready to copy/paste into your Android project. But… you didn’t just skip to the end without reading the article, did you? :-) If you did: don’t ask, read first.

--

--

Dennis Alund
oddbit
Editor for

Google Developer Expert for Firebase, nerd and passionate problem solver | Founder of Kumpul coworking space in Bali