Using Fastlane Tools and Android

The Fastlane tools are great and have really helped the team I’m on streamline our iOS build processes for different variants, both locally and for our CI pipelines. I’m currently working on an Android project and started to explore how I could use the Fastlane tools to improve the project’s build process.

Build Types

For most of our projects we use HockeyApp to help ease distribution of prototypes and in-house apps. Android Studio, by default, provide two build types — debug and release. When I build and upload a version of the app to HockeyApp I wanted make sure that the apk is signed with the same key, so that we don’t run into signing errors. To avoid this, the generated key (and keystore) is added as part of the code repository — so that any other developers and the CI server have it. I then add this snippet to the module’s build.gradle file:

So now, we have a special HockeyApp signing profile. We then need to tell gradle to use this signing configuration when we need it to. This can be done by specifying it in a custom buildType

The release section of buildTypes is provided by default. Debug is too, but it doesn’t show up in the build.gradle file. We added the build type hockeyApp and specify the signing configuration to use when we use the hockeyApp build type.

Now whenever we use the hockeyApp build type the resulting apk will be signed using the android_app_key shown above.

Version Incrementing

One pet peeve of mine is when new versions lack new build (versionCode in Android) and version numbers. Even if the version name (e.g. 1.2 or 1.4) stays the same, it would be nice to know that it’s a different build (e.g. 131 vs 132). Automating this while using gradle and fastlane took some trial and error (and a heck of a lot of googling), so I wanted to share what ended up working best for me.

In the defaultConfig area of build.gradle you should see two keys — versionCode and versionName. The values specified here are injected into the AndroidManfest.xml at compile time and used by the device, the Google Play Store, and others (including HockeyApp) to note build and version changes. I updated my defaultConfig to the following.

Having scoured the web, I found varioius ways of doing automated version incrementing with gradle. The most common is using a properties file within the code base. The readVersion() function in the snippet below reads this properties file and extracts three properties we’ll use for versioning our app — major, minor, and build. The additional functions allow quick access to the versionCode (i.e. build number) and versionName (i.e. major and minor).

To increment the version, both in name and number, we add a few more functions to assist with doing this. The first just increments the build number by 1, while the second takes an argument — type — to denote whether the version will be a major or minor release.

We now need to use all these wonderful functions. Above I showed where to place the read functions, but here is where utilize gradle to do the incrementing. A few more additions to the gradle file — gradle tasks.

The tasks above do exactly what they say they do. So, how do we use them? Since we’re only really interested in updating builds and versions when we’re using Fastlane, we do this via our Fastfile

Here’s where it all comes together! When we run fastlane hockey version:major, first gradle runs the doBuildNumberIncrement task, then it runs the doMajorVersionIncrement task, and finally runs the assembleHockeyApp (i.e. the hockeyApp build type) task After that’s all complete, our resulting APK (which will get uploaded to HockeyApp) will have an updated versionName (e.g. from 1.0 to 2.0) and a new version code (e.g. from 1 to 2).

Bonus

So, if you’re not using Fastlane (although I recommend it) you can still have automated version/build incrementing in Android Studio. Here’s a snippet that does just that. Whenever we build an APK for the build type hockeyApp the versionCode and versionName is updated to that latest in version.properties. You will need to change buildTypes.hockeyApp.name and :app:assembleHockeyApp according to your own project’s build types.

This only handles the buildCode incrementing, but you can do something similar with product flavors or other build types to get minor and major version updates too. Fodder for another post I guess…