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 Jenkinsfile
concise.
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 yaml
files.
In this 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:
The 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
Dockerfile
is found within the project, thatDockerfile
is used, otherwise aDockerfile
that is bundled with the library is used. Allowing me to specify a customDockerfile
is great when I want to use the ndk. The defaultDockerfile
doesn’t include that, since I hardly ever need it. sdkPackage
allows to specify which sdk components are needed for this build. These packages are passed as an argument to theDockerfile
. When omitted, default components specified in theDockerfile
will be used.credential
specifies 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.target
specifies the targets to pass to./gradlew
, has a default ofassemDebug
when omitted.
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.
Please note:
- 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!