Reputation: 3117
We have a release
and debug
buildType and want to set the versionCode
and versionName
to a constant value for debug
as otherwise, every build repackages the apk, even without code changes.
So we set a fixed default versionCode
and later override it for a specific buildType:
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.gradletest"
minSdkVersion 28
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
applicationVariants.all { variant ->
if (!variant.buildType.isDebuggable()) {
variant.outputs.each { output ->
output.versionCodeOverride = getAppVersionCode()
output.versionNameOverride = getAppVersionName()
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.debug
debuggable true
}
}
}
while this works for the apk, unfortunately the generated class BuildConfig
always has the default 1/"1.0"
value. We read and show the versionNumber
from within the app as this popular answer suggests.
Apparently BuildConfig.java
is generated at configuration, not at project build, so it can't know the chosen variant. How to handle this?
Our getAppVersionCode()
is containing a timestamp, so every versionCode is different. I tried flipping the statements, so that the debug builds would show a different versionCode and versionName everytime, which would be fine for us.
android {
defaultConfig {
versionCode getAppVersionName()
versionName getAppVersionCode()
}
applicationVariants.all { variant ->
if (variant.buildType.isDebuggable()) {
variant.outputs.each { output ->
output.versionCodeOverride = 1
output.versionNameOverride = "1.0"
}
}
}
}
The reason why we have a fixed debug versionCode
in the first place is that we don't want to rebuild all submodules for every code change. With the second variant, even though we set a fixed versionNumber
for the debug build through output.versionCodeOverride = 1
all submodules are rebuild by Android Studio. Before Android Studio 3.0 this worked but doesn't anymore. Please advise.
Upvotes: 4
Views: 1518
Reputation: 323
As you noticed, BuildConfig.VERSION_NAME
and BuildConfig.VERSION_CODE
are automatic config fields that get set at time of configuration and unfortunately are not affected by using gradle scripts to set output override values.
Because they are automatic config fields, they also cannot be directly changed via gradle scripts either. Fortunately there are ways around this when using your approach:
1) Get the real version values for display from package manager:
Instead of calling BuildConfig.VERSION_NAME
and BuildConfig.VERSION_CODE
where you need to display them in app, call
val versionName: String = context.packageManager.getPackageInfo(context.packageName, 0).versionName
val versionCode: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.packageManager.getPackageInfo(context.packageName, 0).longVersionCode.toInt()
} else {
context.packageManager.getPackageInfo(context.packageName, 0).versionCode
}
This will return the version values that you set via output.versionCodeOverride
for the selected variant, even though the BuildConfig fields default to "1.0"/1
2) Add your own BuildConfig fields for app version
If you really want the version name to be accessible from BuildConfig, you can just build additional config fields when you set the output override values. Just be sure that you do NOT use the automatic field names of VERSION_NAME
and VERSION_CODE
:
android {
...
applicationVariants.all { variant ->
if (variant.buildType.isDebuggable()) {
variant.outputs.each { output ->
output.versionCodeOverride = 1
output.versionNameOverride = "1.0"
}
variant.buildConfigField("String", "REAL_VERSION_NAME", "\"${getAppVersionName()}\"")
variant.buildConfigField("Int", "REAL_VERSION_CODE", ${getAppVersionCode()})
}
}
}
then access using
val versionName: String = BuildConfig.REAL_VERSION_NAME
val versionCode: Int = BuildConfig.REAL_VERSION_CODE
Upvotes: 2