Continuous Delivery for Android
For a long time I’ve been in search of a good continuous integration server for Android. I’ve even written about one that I used years ago, which is no longer suited to Android development, in my opinion.
As the Android community has grown, so has the wealth of tools available. In that time I’ve also moved from simply wanting continuous integration, to wanting continuous delivery.
Continuous Delivery you say?⌗
Continuous delivery builds on continuous integration, but instead of just testing your source code when you commit, it is also published to the appropriate channels. This takes the burden from the developer by automatically releasing a new version of the app any time changes are made, and also creates a reliable, repeatable release pipeline.
When I initially considered continuous delivery it seemed better suited to web apps since they don’t burden the user with an install any time there is a new version. Once I thought about it some more I realized that I had been assuming that you always release to production, but the idea of continuous delivery makes no assumptions about where the app will be delivered.
Release Targets⌗
I found it important to identify when and where I needed releases of the app to be available, and also consider the makeup of the team. In the case of Pixite, our Android team consists of myself and a designer. Our workflow usually consists of me working on features or fixing bugs, iterating with the designer, then releasing the app internally, then to beta and production.
Pigment also makes use of a debug drawer, which allows test users (usually me or the designer) to change environments, toggle subscription status, and do other useful things. This drawer only exists in debug builds, so can’t be made available through the Play Store.
This means that I need two built types to be available. Debug, so my designer and I can test and iterate quickly on features, and Release, so the rest of the team, and the beta testers, can test what will actually go to production.
Continuous Integration⌗
The first step in our workflow is continuous integration. I use CircleCI. After several months dealing with managing a Jenkins server, I felt my time was better spent with a hosted solution, and CircleCI 2.0’s Workflow structure fit the bill nicely.
I found Chris Banes’ Tivi app a great starting point for my own config.yaml file, which you can see in this gist.
Github has made it incredibly easy to integration third party testing platforms in your repos by simply following the instructions on the Github Marketplace.
Debug Builds⌗
With only a single developer the debug build case turns out to be pretty easy, since there aren’t usually overlapping features appearing in feature branches in Github at once. Therefore, I set up CircleCI to build and release a debug build any time a commit is pushed to a non-master branch. This means that any updates to feature branches get automatically deployed, allowing for quick iteration.
Since debug builds can’t be published to Google Play, I chose to use the other leader in beta deployment, Crashlytics Beta. With the Beta app installed, my designers gets notified any time a new debug build is available, and can quickly test the new feature and provide feedback.
The Crashlytics gradle plugin comes with a handy action, crashlyticsUploadDistributionDebug
, to deploy debug builds directly to Crashlytics Beta. This makes automation super simple.
Release Builds⌗
Once features are ready and PRs are merged into master (yes, I use pull requests with one developer) release builds get sent to the alpha channel of the Play Store. This is distributed to the Pixite team, allowing everyone to check out the latest release build before it goes to beta.
Automating releases to Google Play is pretty easy, thanks to the Gradle Play Publisher plugin from Triple-T. This plugin adds gradle tasks that allow you to automatically release to any track in the Play Store, including listing information like descriptions and screenshots (which should be version controlled, anyway).
Google Play recently introduced the Internal test release target, intended for a small group of testers to gain quick access to releases. The Gradle Play Publisher plugins doesn’t yet have a release version that supports this so, for now, I’m still using an Alpha test group.
From the Alpha channel, it’s a couple of button presses to move the build through the beta channel, then to production. I usually leave builds in beta for at least a week or two while I evaluate feedback and reports from beta testers, and fix up any final bugs.
Reducing Tedious Tasks⌗
Especially in teams of limited size, it’s important to reduce the number of tedious tasks each person has to do so they can spend their time on more valuable tasks. In my case, setting up a reliable continuous delivery system lifted a lot of the burden of cutting releases, notifying everyone that needs to know, and making sure they know the correct version that they need. That means I get to spend more time improving Pigment and adding new features, which is much more fun.