I would like to have a task that increments versionCode and proceeds with the build.
I can’t get this to work, because the android {}
closure is apparently evaluated before any tasks are run, and I can’t seem to change the values properly after that point.
Build script
I tried to keep this as minimal as possible, but it’s still pretty big.
// Boilerplate
buildscript {
repositories { jcenter() }
dependencies { classpath 'com.android.tools.build:gradle:1.3.0' }
}
allprojects { repositories { jcenter() } }
// Version management
def showCurrentCustomVersion() {
println(" currentDynamicVersionCode = ${project.ext.loadCurrentDynamicVersionCode()} (${project.ext.currentDynamicVersionCode})")
println(" android.defaultConfig.versionCode = ${android.defaultConfig.versionCode}")
}
project.ext.currentDynamicVersionCode = 10
project.ext.loadCurrentDynamicVersionCode = {
// In my full script, this loads the version code from a file
return project.ext.currentDynamicVersionCode
}
task changeCustomVersionCode << {
println("*** Before changeCustomVersionCode:")
showCurrentCustomVersion()
// In my full script, this loads the version code from a file, increments it, and saves it back to the file for future use
project.ext.currentDynamicVersionCode = 99000
android.defaultConfig.versionCode project.ext.loadCurrentDynamicVersionCode()
// Also tried this, but had the same result:
//android.defaultConfig.versionCode = project.ext.loadCurrentDynamicVersionCode()
println("*** After changeCustomVersionCode:")
showCurrentCustomVersion()
println("=> android.defaultConfig:\n ${android.defaultConfig}")
println("=> android.buildType:\n ${android.buildTypes}")
println("=> android.productFlavors:\n ${android.productFlavors}")
}
// Android
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.snobwall.buildtest"
minSdkVersion 21
targetSdkVersion 22
versionCode project.ext.loadCurrentDynamicVersionCode()
versionName "1.0"
}
}
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) }
task changeCustomVersionAndBuild(dependsOn: changeCustomVersionCode)
gradle.projectsEvaluated {
changeCustomVersionAndBuild.dependsOn assembleRelease
assembleRelease.mustRunAfter(changeCustomVersionCode)
}
Relevant output
The versionCode appears to be changed correctly here.
:changeCustomVersionCode
*** Before changeCustomVersionCode:
currentDynamicVersionCode = 10 (10)
android.defaultConfig.versionCode = 10
*** After changeCustomVersionCode:
currentDynamicVersionCode = 99000 (99000)
android.defaultConfig.versionCode = 99000
=> android.defaultConfig:
ProductFlavor_Decorated{name=main, dimension=null, minSdkVersion=ApiVersionImpl{mApiLevel=21, mCodename='null'}, targetSdkVersion=ApiVersionImpl{mApiLevel=22, mCodename='null'}, renderscriptTargetApi=null, renderscriptSupportModeEnabled=null, renderscriptNdkModeEnabled=null, versionCode=99000, versionName=1.0, applicationId=com.snobwall.buildtest, testApplicationId=null, testInstrumentationRunner=null, testInstrumentationRunnerArguments={}, testHandleProfiling=null, testFunctionalTest=null, signingConfig=null, resConfig=[], mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}}
=> android.buildType:
[BuildType_Decorated{name=debug, debuggable=true, testCoverageEnabled=false, jniDebuggable=false, pseudoLocalesEnabled=false, renderscriptDebuggable=false, renderscriptOptimLevel=3, applicationIdSuffix=null, versionNameSuffix=null, minifyEnabled=false, zipAlignEnabled=true, signingConfig=SigningConfig_Decorated{name=debug, storeFile=/Users/mrb/.android/debug.keystore, storePassword=android, keyAlias=AndroidDebugKey, keyPassword=android, storeType=/Users/mrb/.android/debug.keystore}, embedMicroApp=false, mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}}, BuildType_Decorated{name=release, debuggable=false, testCoverageEnabled=false, jniDebuggable=false, pseudoLocalesEnabled=false, renderscriptDebuggable=false, renderscriptOptimLevel=3, applicationIdSuffix=null, versionNameSuffix=null, minifyEnabled=false, zipAlignEnabled=true, signingConfig=null, embedMicroApp=true, mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}}]
=> android.productFlavors:
[]
:preBuild UP-TO-DATE
:preReleaseBuild UP-TO-DATE
--- snip ---
:assembleRelease
:changeCustomVersionAndBuild
BUILD SUCCESSFUL
Resulting APK
No luck here; uses version 10 instead of 99000.
$ aapt d badging build/outputs/apk/app-release-unsigned.apk | fgrep versionCode
package: name='com.snobwall.buildtest' versionCode='10' versionName='1.0' platformBuildVersionName='5.1.1-1819727'
What I tried
-
Use a lazy GString for the versionCode, but Android expects an int there (not a string).
-
Call
apply plugin:
andandroid {}
from within the task (instead of at project scope). This caused something to crash internally (in the Android project, I believe). I also don’t know what effect this would have on the project evaluation process: Wouldgradle.projectsEvaluated
be invoked twice? -
Use a separate prebuild script to perform versioning tasks, then chain to the app build script. This works, but is awkward and feels like a hack.
-
Poke at the android object to see if there’s anything else I can change. For example, maybe other configs are created using
defaultConfig
as a template. I didn’t see anything relevant though. (Some of these are visible in the output above) -
Browse this Android DSL reference to see if there’s anything else I might be able to poke at.
My knowledge of Gradle script debugging is too weak for me to get any deeper. I suspect that the Android plugin may be creating some tasks with closures that have captured the versionCode value anonymously; if that’s true, I may be forever unable to change it once the android {}
closure has been evaluated.
Hoping for any suggestions!