Android Gradle: Dynamically change versionName at build time
That's what buildTypes
are for. What you're describing is a release
build, IMO.
Here's an example: when executing assembleDebug
it will give you a snapshot build, and executing assembleRelease
will give you a clean build without any suffix and incremented version number. The next debug build will also use the incremented number.
The following is a fully functional build when the files are created in a folder. It should also work with flavors, but that's just a side product :). Gradle 2.2.1, Android plugin 1.1.3
build.gradle
apply plugin: 'com.android.application'apply from: 'auto-version.gradle'buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.1.3' }}android { buildToolsVersion = "21.1.2" compileSdkVersion = "android-21" buildTypes { debug { versionNameSuffix "-SNAPSHOT" } }}println "config code: ${calculateVersionCode()}, name: ${calculateVersionName()}"
src/main/AndroidManifest.xml
<manifest package="com.example" />
auto-version.gradle
ext { versionFile = new File(project.rootDir, 'version.properties') calculateVersionName = { def version = readVersion() return "${version['major']}.${version['minor']}.${version['build']}" } calculateVersionCode = { def version = readVersion() def major = version['major'] as int // 1..∞ def minor = version['minor'] as int // 0..99 def build = version['build'] as int // 0..999 return (major * 100 + minor) * 1000 + build }}Properties readVersion() { def version = new Properties() def stream try { stream = new FileInputStream(versionFile) version.load(stream) } catch (FileNotFoundException ignore) { } finally { if (stream != null) stream.close() } // safety defaults in case file is missing if(!version['major']) version['major'] = "1" if(!version['minor']) version['minor'] = "0" if(!version['build']) version['build'] = "0" return version}void incrementVersionNumber() { def version = readVersion() // careful with the types, culprits: "9"++ = ":", "9" + 1 = "91" def build = version['build'] as int build++ version['build'] = build.toString() def stream = new FileOutputStream(versionFile) try { version.store(stream, null) } finally { stream.close() }}task incrementVersion { description "Increments build counter in ${versionFile}" doFirst { incrementVersionNumber() }}if (plugins.hasPlugin('android') || plugins.hasPlugin('android-library')) { android { defaultConfig { versionName = calculateVersionName() versionCode = calculateVersionCode() } afterEvaluate { def autoIncrementVariant = { variant -> if (variant.buildType.name == buildTypes.release.name) { // don't increment on debug builds variant.preBuild.dependsOn incrementVersion incrementVersion.doLast { variant.mergedFlavor.versionName = calculateVersionName() variant.mergedFlavor.versionCode = calculateVersionCode() } } } if (plugins.hasPlugin('android')) { applicationVariants.all { variant -> autoIncrementVariant(variant) } } if (plugins.hasPlugin('android-library')) { libraryVariants.all { variant -> autoIncrementVariant(variant) } } } }}
Execute gradle assembleDebug
to build normally, gradle assembleRelease
to increment and build, and gradle incrementVersion
to just increment.Note: be careful with gradle assemble
because the order of assembleDebug
and assembleRelease
will yield different results.
Check the generated files in the build
directory to see if the values are to your liking.
Manual execution (from comments)
It is possible you have multiple flavors in which case the version is incremented multiple times because multiple variants match the release build type. The original quesion was for no flavors. If you want to have more control when the version number is incremented just remove the afterEvaluate
block and call the incrementVersion
task whenever you want:
gradle incrementVersion assembleFreeRelease assemblePaidRelease
(The above manual execution is an untested idea.)
Check uncommitted changes
The "Check uncommitted changes" are not covered in this answer, that's another game. You could hook on to tasks.preBuild.doFirst { /*fail here if uncommited changes*/ }
if I understand correctly. But that highly depends on your version control. Ask another question for more!
I needed to append current git commit count of code revision to the version name. Its real handy in many situation. I ended up with below simple gradle file
apply plugin: 'com.android.application'android { compileSdkVersion 21 buildToolsVersion "21.1.2" def gitCommitCount = "git rev-list HEAD --count".execute().text.trim() defaultConfig { applicationId "my.app.package.name" minSdkVersion 16 targetSdkVersion 21 versionCode 6 versionName "0.8" } buildTypes { debug { versionNameSuffix ".${gitCommitCount}" } release { versionNameSuffix ".${gitCommitCount}" minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } }}
Similar to gitCommitCount, You can generate variables of your own to customise version name. As i am just executing a terminal command to store its result in a variable.
This doesn't directly address your question of how to completely change the versionName, but this is what I use to append a suffix for my buildTypes:
defaultConfig { versionName "1.0"}buildTypes { debug { versionNameSuffix "-SNAPSHOT" }}