https://www.jayway.com/2015/03/11/automatic-versioncode-generation-in-android-gradle/
In this post I’ll show you how to setup Gradle for an Android project to automatically generate a usable versionCode
from a standardized version number.
The problem
The Android Gradle build system is wonderful, with a good balance between sane defaults, readability and extensibility. However, handling of versionCode
and versionName
isn’t as automatic as one often would like. Thanks to the dynamic Groovy foundation of Gradle this issue is easy to remedy.
One problem is that you often want to implement a sane pattern of generating the versionCode
value. This isn’t as easy as it might appear as there are a couple of things to take into consideration, many of which ties into how Google Play handles the versionCode
.
- The version code needs to increase for each release.
- You can only upload one APK per version code, so it needs to be unique for each release.
- Sometimes you want to use Release Candidates for alpha and beta testing, so these needs to have unique version codes.
- The version codes of your Release Candidates must however be lesser than the version code of the final release.
- You also want to be able to release point/patch releases of older apps, with lesser version codes than the latest version.
The last point is especially interesting due to the nature of the minSdkVersion value. To summarize this problem: you might have older version of your app active on Google Play, since these run on older devices than your latest version. If a bug appears, you want to be able to push out a fix even for these older versions, with a version code lower than the latest version.
The solution
The solution to all of this is to adapt a standardized versioning schema. There’s no need to use a too complex schema; we just want something that covers our use case. The chosen schema is therefore a simplified version of the Maven versioning schema. This schema uses Major, Minor and Patch versions, together with -SNAPSHOT and -RC suffixes. Versions will look like “1.0.1”, “1.2.0-SNAPSHOT”, “2.4.0-RC1” and so on.
- The Major version denotes major changes to the app. If large parts are rewritten it warrants a Major version bump.
- The Minor version denotes public releases. Each time a version has been released this number is bumped.
- The Patch version denotes bug fixes and patches. It’s only ever used if an existing release needs to be amended.
- “-SNAPSHOT” is used during development. These versions are never put on Google Play.
- “-RC*” denotes Release Candidates. These are used during final testing, when the app is distributed externally, but not yet publicly. They lead up to the final release.
- No suffix denotes a final release. The version code should always be higher than any Release Candidate.
The version name needs to be translated into a version code. We do this by allocating two digits to each version segment. That gives us 100 values for each one, with the Major version taking the highest numbers and the suffixes taking the lowest number.
So, version “1.2.3-SNAPSHOT” would then result in version code 1020300, whereas version “1.2.3-RC4” would result in version code 1020304. Final releases always gets assigned 99 as their last code, to make sure that they always have a higher version code than Release Candidates.
Example
Consider us working on our app, and that we’re currently working on version 1.2.0-SNAPSHOT. The version code is 1020000. As release nears we want to do a first test with a selection of users on Google Play, and we therefore change the version to 1.2.0-RC1, tag it, build it and put in on the alpha or beta channel on Google Play. Version code is now 1020001. Perhaps we need more fixes, so we do a 1.2.0-RC2 release. Version code is now 1020002.
Everything now looks good, so we change the version to 1.2.0, the final release, and pushes this to Google Play. Version code is now 1020099.
As soon as this is done we start on the next iteration, which is version 1.3.0-SNAPSHOT. Version code is 1030000. After some days a bug is found in the released version, and we need to push out a quick fix. We do this by creating a “1.2” branch from the latest release tag, fixing the bug, and set the version name to 1.2.1. Version code is 1020199.
Implementation
So, how to implement all of this in a smooth way? One approach is to do all of this manually. That’s of course doable, but we much rather make sure that as much as possible is automated. Gradle to the rescue then!
In our Android Gradle project we’ll start by seting the version in the gradle.properties
file at the top level. Why? Well, because it’s a convention and there are existing Gradle tools which works with this approach. Thus, gradle.properties
now contains
Gradle will automatically read from this file and make the version
value available.
Now we have to add some code which can parse the version value and produce a versionCode
value in accordance to the rules set up above. Create a file named versioning.gradle
and put this code into it
This code isn’t activated by default, so we need to tell Gradle to do that. Alter the top level build.gradle
file and add this line
Now for the final step; to configure the Android plugin. Edit the app/build.gradle
file and change the android.defaultConfig
section to read
And there you have it!
An example of this can be seen in this simple example project.
All code licensed under CC0.