In Android Studio I have in build.gradle default info about application version:
android {
defaultConfig {
versionCode 24
versionName "0.1 beta"
}
}
How can I increment the versionCode automatilcally on each project compilation?
Quoting from my book:
Since the android:versionCode is a monotonically increasing integer,
one approach for automating it is to simply increment it on each build.
While this may seem wasteful, two billion builds is a lot of builds,
so a solo developer is unlikely to run out. Synchronizing such versionCode
values across a team will get a bit more complex, but for an individual
case (developer, build server, etc.), it is eminently doable using Groovy.
The
Gradle/HelloVersioning
sample project uses a version.properties file as the backing store for the
version information:
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def code = versionProps['VERSION_CODE'].toInteger() + 1
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode code
versionName "1.1"
minSdkVersion 14
targetSdkVersion 18
}
}
else {
throw new GradleException("Could not read version.properties!")
}
First, we try to open a version.properties file and fail if it does not
exist, requiring the developer to create a starter file manually:
VERSION_CODE=1
Of course, a more robust implementation of this script would handle this case and
supply a starter value for the developer.
The script then uses the read-the-custom-properties logic illustrated
in the preceding section [NOTE: of the book, not included here] to read the existing
value... but it increments the old value by 1 to get the new code to use.
The revised code is then written back to the properties file before it
is applied in the defaultConfig block.
In this case, the script throws a GradleException to halt the build if
the version.properties file could not be found or otherwise could not be
read.
Related
I just made a new Android bundle for my React Native app. I manually updated the version code from 90 to 91 in android/app/build.gradle, but now that I am trying to upload to Play Store, the version code is 3145819 (I expected to see 91)
build.gradle:
defaultConfig {
applicationId "com.myapp"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 91
versionName "4.1.0"
multiDexEnabled true
missingDimensionStrategy "RNN.reactNativeVersion", "reactNative57_5"
resValue "string", "build_config_package", "com.myapp"
}
I use this command to bundle:
./gradlew bundleProdRelease --console plain
Not sure why this is happening, and I definitely prefer a smaller version code (easier for users to read when reporting bugs).
Any idea what's going on here and how to fix it?
Ohhh ok I finally figured it out! No, I haven't been desperately looking for an answer for the past two years... I just somehow stumbled upon it now.
So, in android/app/build.gradle, there is a script that generates the bundle version code. It's calculated from the version code and the target architecture version code. For example in the RN 0.64x template:
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) {
output.versionCodeOverride = defaultConfig.versionCode * 1000 + versionCodes.get(abi)
}
For me, arm64-v8a always seems to get used as the default when generating the version code, so I get outputs like:
versionCode 1 => 1003
versionCode 12 => 12003
versionCode 105 => 105003
you get the idea...
The calculation used to involve a much more mysterious number (1048576 🔮🧙♂️, see in the RN 0.59x template), which seemed arbitrary and made it quite tricky to understand how this bundle version code was generated.
Now it makes much more sense!
One possibility is that your /app/build.gradle config contains some logic that transforms the versionCode likely because you are doing app bundling.
In the current master of react-native, you can see some versioning logic here.
Possibly your build.gradle has the same or similar logic.
Google has there explanation on versioning here.
I had the same issue. It occurred whenever I ran ./gradlew bundleRelease and I changed
def enableSeparateBuildPerCPUArchitecture = false
to
def enableSeparateBuildPerCPUArchitecture = true
This function is found in android/app/build.gradle
I am unsure how to stop it doing it aside from changing enableSeparateBuildPerCPUArchitecture back to false
The versionCode for the android apk gets set in defaultConfig. I would like to change for each of my build types but it seems like this can only be done by flavours? Is there another way to override the versionCode, maybe similar to the way the outputFileName is updated?
I think your case fit perfectly with product flavors.
You set a flavor for prod and a flavor for stage. In both set version code as your expression (e.g. 300 + android.defaultConfig.versionCode for prod, and 200 + android.defaultConfig.versionCode for release)
See the doc for detailed examples:
https://developer.android.com/studio/build/build-variants
Then, when you want to run or deploy a version you choose between the 4 combinations in Build Variants that will be: prodRelease, prodDebug, stageRelease and stageDebug
You can create different AndroidManifest.xml for each buildType you have, and then set the versionCode in the manifest, but in my personal opinion you should use flavors.
In your project root build.gradle you could define version code and version Name some thing like this
def code = project.hasProperty('versionCode') ? versionCode.toInteger() :
(System.getenv("VERSION_CODE") as Integer ?: <default-version-code>)
def name = project.hasProperty('versionName') ? versionName.toString() :
(System.getenv("VERSION_NAME") as String ?: "<default-version-name>")
You could provide version code and name runtime in the build command something like this
-P = value
allprojects {
ext.baseVersionCode = code
ext.baseVersionName = name
}
These version code your could access in you all modules.In the app build.gradle
defaultConfig {
versionCode baseVersionCode
versionName baseVersionName
archivesBaseName = "customzied_apk_name"
}
After updating to AGP(Android Gradle Plugin) 3.2.0 we can't set versionCode directly on a mergedFlavor. If we do so we get this useful warning:
versionCode cannot be set on a mergedFlavor directly.
versionCodeOverride can instead be set for variant outputs using the following syntax:
android {
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.versionCodeOverride = 40805
}
}
}
After this change everything works fine besides one little thing. The auto-generated BuildConfig.VERSION_CODE doesn't reflect the version code from output.versionCodeOverride = 40805.
Before AGP 3.2.0 we could set the versionCode dynamically through:
applicationVariants.all { v ->
v.mergedFlavor.versionCode = 40805 // 40805 is hardcoded as an example but it is archived dynamically.
}
And the version code reflected in BuildConfig.VERSION_CODE (this is very handy) and I would like to archive the same with AGP 3.2.0.
I know I could workaround this by creating a custom build config field for this like variant.buildConfigField('int', 'OVERRIDDEN_VERSION_CODE', "${versionCodeOverride}") and this will generate the BuildConfig.OVERRIDDEN_VERSION_CODE with the versionCode I override. Archiving the same as I was when using the AGP version bellow 3.2.0 by setting the versionCode through mergedFlavor.versionCode = 40805 but I don't like this kind of workarounds.
Is there any way to have the output.versionCodeOverride = 40805 being reflecting in the auto-generated BuildConfig.VERSION_CODE?
PS: If we set the versionCode directly in the specific flavor it will work as expected but that's not what I want to know :)
UPDATE
Found a similar question(with a well described use case) and considering the discussions we had I could give a better answer here.
To recap, the problem isn't the version code override not being applied at all, it's just that BuildConfig.VERSION_CODE does not pick up the override value.
This has been labeled as intended behavior in the official issue tracker: https://issuetracker.google.com/issues/37008496
One of the comments explains why and suggests defining versionCode in a flavor instead of the defaultConfig:
If we made a different buildconfig.java per output then we'd also need to run javac/proguard/jacoco/dex for each split and we'd lose the improvement in build [time].
If this is critical to you, then don't use splits and use flavors instead, but we'll get much slower build time.
If you don't want to alter your curent setup you might want to read the version code from the manifest instead. All you need is a context:
val versionCode = context.packageManager.getPackageInfo(context.packageName, 0).versionCode
You should cache the value as getting package info is a non-trivial operation.
The same applies to version name.
the order of instructions is important there ...
String versionName = version.versionName
int versionCode = version.versionCode
android {
applicationVariants.all { variant ->
// to be removed here:
// variant.mergedFlavor.versionCode = versionCode
variant.outputs.each { output ->
// and to be added here:
output.versionNameOverride = versionName
output.versionCodeOverride = versionCode
}
}
}
the documentation for Build multiple APKs explain it, below "Configure versioning".
while the reason for this isn't build-tools 3.2.0, but it's Gradle 4.6.
in an Android app I did not develop, but I have to edit, I found this gradle script:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.ajoberstar:grgit:1.5.0'
}
}
import org.ajoberstar.grgit.Grgit
ext {
git = Grgit.open(currentDir: projectDir)
gitVersionName = git.describe()
gitVersionCode = git.tag.list().size()
gitVersionCodeTime = git.head().time
}
task printVersion() {
println("Version Name: $gitVersionName")
println("Version Code: $gitVersionCode")
println("Version Code Time: $gitVersionCodeTime")
}
The "gitVersionCode" variable is used as "versionCode" of the app in the build.gradle file.
This is the build.gradle file:
// gradle script
apply from: "$project.rootDir/tools/script-git-version.gradle"
//...
defaultConfig {
applicationId "..."
minSdkVersion 17
targetSdkVersion 25
versionCode gitVersionCode
versionName gitVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
When I generate signed APK and try to add to beta version, I get the google error that "Version code already exists", but I do not know how to edit the version code of the app.
My questions are:
what this code actually does?
how to edit the version code of the app?
Git is a version control system. Your project appears to be stored in a Git repository.
Grgit is a Groovy library that works with Git. Your Gradle script is loading this library.
git is an instance of Grgit. git.tag.list() returns a list of the Git tags used in this repository. git.tag.list().size() returns the number of tags in that list.
So, this Gradle script is setting the versionCode to be the number of Git tags used in the project's Git repository.
how to edit the version code of the app?
Either:
Create another Git tag, such as by tagging the version that you are trying to release, or
Change versionCode gitVersionCode to stop using gitVersionCode and use some other numbering system
It appears to be using this library to query git, in order to generate the version name and version code. In terms of the version code, it looks like it's setting it depending on the number of git tags it finds. So, to bump the version code, do a git tag on your release commit.
If that doesn't suit, you could just do it manually and replace
versionCode gitVersionCode
with
versionCode 99
replacing "99" with whatever your version code should be.
I have an Android that I deploy to a Google Play alpha track trough a CI server. For the Android versionCode I make use of the CI build number that I inject into the Gradle script through an environment variable.
This used to work fine; but currently Google Play is not accepting any builds. When I manually trigger a alpha upload build (using the gradle-play-publisher plugin) for Gradle I eventually end up with the following error:
APK has an invalid version code.
So when looking (using aapt dump badging apk-path) at the generated APK I see an empty value for the version code (versionCode='').
The relevant code from the build script:
def appVersionCode = System.getenv("BUILD_NUMBER") as Integer ?: 0
defaultConfig {
...
versionCode appVersionCode
...
}
It seems the variable is not read correctly; however it reads System.getenv("KEY_PASS") correctly to use for signing.
The variable is also set:
❯ echo $BUILD_NUMBER
1234
Does anyone have an idea why this specific variable doesn't seem to be read (anymore)?
Gradle version: 3.5 with Android Gradle plugin 2.3.1.
Try to change your code to this:
def appVersionCode = Integer.valueOf(System.env.BUILD_NUMBER ?: 0)
defaultConfig {
...
versionCode appVersionCode
...
}