A1m
A1m

Reputation: 3117

android-gradle set versionNameOverride does not set versionName in BuildConfig.java

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

Answers (1)

Brian Acker
Brian Acker

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

Related Questions