If you are building Android apps, you can’t really go without a continuous integration system (ci) to
compile your code, run your tests and automate various other tasks. There are many ci systems out there,
but for my personal projects I tend to rely on a Jenkins instance that I host myself. I’m using a little shared library
I created to make building Android apps easier, while keeping the
A Jekins pipeline
In Jenkins you define pipelines to build your software. The pipeline definition is kept in
Jenkinsfile that you check in
with your project, effectively “configuration as code” that most other ci systems provide in
Jenkinsfile you then describe every step that Jenkins should take to build your project.
You can customise the dsl (the definition of the steps) in that
Jenkinsfile using shared libraries.
This allows for a common
way to configure and build your projects. The library itself is pulled from a git repository, so you can update the
library independently of your projects. These libraries are configured in the Jenkins main settings.
A common Android pipeline
Looking at my personal (reasonably small) projects, I have a few common steps that I’d like to perform on ci:
- Make sure the required Android sdk components, like build tools and target plaforms are installed
- Run tests with reports
- Run lint checks with reports
- Build a release version of my build and sign it using credentials that I store in Jenkins
- Archive the apk, bundle and ProGuard mapping files, as I need those files when uploading to the Play Store or for testing.
All of my Android builds run in a Docker container that I use to setup the correct environment. That has the benefit of it being
relatively self contained: all you need is the
Dockerfile and you should be able to build the project within that container,
using Jenkins or something else.
The library I created for my Jenkins instance captures these common steps.
A sample Jenkinsfile
With the library in place, my
Jenkinsfile looks something like this:
android block is not a standard Jenkins construct; it’s defined in the pipeline library. When this pipeline runs,
a couple of things happen:
- A Docker container is built. If a
Dockerfileis found within the project, that
Dockerfileis used, otherwise a
Dockerfilethat is bundled with the library is used. Allowing me to specify a custom
Dockerfileis great when I want to use the ndk. The default
Dockerfiledoesn’t include that, since I hardly ever need it.
sdkPackageallows to specify which sdk components are needed for this build. These packages are passed as an argument to the
Dockerfile. When omitted, default components specified in the
Dockerfilewill be used.
credentialspecifies what credentials (secrets) to use for this build. In Jenkins a credential has an id and a secret text. The second argument is as a project property that is set using an environment variable for the Gradle build, passing in the secret that way.
targetspecifies the targets to pass to
./gradlew, has a default of
For every build, test and lint reports are collected and artifacts are archived.
Try it yourself
You can find a copy of my current pipeline library here. If you have a working Jenkins setup with pipelines and builds using Docker it should work on your Jenkins instance too.
- While it works for my personal setup, it lacks some checking of values that you’d probably want if you are deploying this to a greater audience.
- This serves merely as an example, I’m not planning to update or maintain this example!
- If want to use this library as is, please make sure to fork it. Referencing pipeline libraries on your Jenkins instance that you do not control are considered a security risk as the library can change at any moment, affecting your builds.
I hope this will give you some ideas how to add your own shared library or how you can customise this even further!