Continuous Integration for Android
- Getting Started
- Understanding Continuous Integration
- Workings of a Continuous Integration System
- Working With a Docker Container
- GitHub Actions
- Understanding the GitHub Actions Workflow
- Setting up GitHub Actions for Android
- Defining Workflows and Jobs
- Running Unit Tests
- Running Instrumentation Tests
- Generating the APK File
- Code Coverage
- Setting up the JaCoCo Plugin
- Making the Build Fail
- Where to Go From Here?
The master branch in a repository is generally the most stable of all the branches. Developers should be able to make a production-ready (or equivalent) build out of it — which means the master branch has to have fully-verified and battle-tested code. But how can you be sure that’s the case?
That’s where CI comes in! CI, short for continuous integration, is a development practice in which each member of a team frequently merges their codes into the main repository branch. Each integration triggers an automated build and test workflow, allowing the team to detect and fix problems as early as possible.
In this tutorial, you’ll learn how to implement continuous integration for Android in an app called Simple Calculator.
In the process, you’ll learn to:
- Implement CI in your workflow.
- Use GitHub Actions.
- Integrate testing frameworks to compliment the CI workflow.
- Use code coverage tools like JaCoCo — and learn why they’re important.
Click the Download Materials button at the top or bottom of the page to download the starter project. Launch Android Studio 4.0 or later and select Open an existing Android Studio project, then navigate to and open the starter project’s folder.
Build and run the app, then take some time to use it and then familiarize yourself with its code.
Now, take a look at the starter project. It contains the following files:
For example, clicking on any numerical or decimal button appends a tag that holds the value that corresponds to the input field of the calculator.
- Calculate.kt is an interface that all the singleton classes in the operators package implement.
MainActivity.kt handles the UI interactions. Each button inside the
ConstraintLayouthas a common
View.OnClickListenerand a tag associated with it. When the user clicks a button, it invokes the
onClick(), which uses the tag of the clicked view to decide how to handle it.
- CalculatorEngine.kt is the core of the app, driving the calculation. Based on the input operator, it delegates the calculation to corresponding classes and updates the result with the output of the calculation.
Start the emulator and run both unit and instrumentation tests. Don’t forget to turn off device animations before running instrumentation tests since these often depend on the UI to work properly.
Take some time to explore the files inside app/build, which will be important in the upcoming sections.
Now, it’s time to start implementing continuous integration for Android.
Understanding Continuous Integration
Since the master branch has to be stable at any given time, no developer should push their commits directly to that branch. When working on a new feature, you must create a new branch from the master then work on that branch.
When you’re done, you pull changes from the main branch into yours, resolve any merge conflicts then push that branch to the project repository. Multiple developers working on the same repository should all follow that same pattern.
To keep your branch updated, you need to pull changes from the main branch frequently. This also saves you from huge merge conflicts.
When you push your changes to your repository, you trigger the CI workflow that runs the test cases. You can only merge your commit to the master after the code passes the tests.
If the tests fail, you have to hunt for the errors using the CI logs, fix them and repeat those steps. This ensures that only tested and working code gets to the master branch.
So now that you understand the theory, it’s time to look at how to put CI into practice.
Workings of a Continuous Integration System
Most CI providers use virtual machines and/or lightweight abstractions called containers. Containers allow a developer to package an application and all its required dependencies and deploy it as one package. For example, you could package a web application that runs on Java with the Java Runtime Environment.
A popular containerization tool is Docker. When you use Docker, you distribute the containers as a Docker image.
For this tutorial, you’ll use a Docker image to spawn the Ubuntu OS without an user interface. Inside the container, you’ll use
apt-get to set up necessary tools like Git and Gradle. With them installed, you’ll be able to clone your Android project from the repository, build the project and a lot more. The caveat is that since there is no interface, you’ll have to use the CLI (Command Line Interface).
In the next step, you’ll go behind-the-scenes of what happens inside a CI machine.
Working With a Docker Container
Follow the official guides to set Docker up on your system. Once you install it, you’ll be able to run Ubuntu on top of your OS. Just open a terminal window and enter the command below:
docker run -it ubuntu:latest
With this command, you download the ubuntu image with the
latest tag from DockerHub, if it’s not available locally. You then run it in interactive mode — that is, you get access to the container’s terminal.
Great! You now have an Ubuntu OS running on top of your OS, ready to run your commands.
docker imagescommand to list all the downloaded images and
docker psto list the running containers. You can find other useful Docker commands in our tutorial, Getting Started with Docker.
Next, you’ll enter the following command:
apt-get update apt-get install git-all
The first command makes sure all your packages are currently updated and the second installs Git in your docker container.
To install Gradle, follow Linuxize’s directions on installing Gradle on Ubuntu.
The bottom line is that you’ll be presented with a lightweight OS and all you need to do is provide the commands for it to execute.
However, since you’ll be using some third-party providers for this tutorial, you won’t need to deal with Docker directly and most likely won’t need to install standard tools like Git. But the tools like Gradle and JDK (Java Development Kit) are unlikely to be provided. If so, you need to manually set these up in the container.
In the next section, you’ll learn how to use GitHub’s automation tool: GitHub Actions.