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"
}
Related
I have old apps using non compliant applicationId. I trying to migrate them with flavorDimensions to share so common assets & code.
I have this flavors setup :
defaultConfig {
applicationId "com.example"
}
flavorDimensions 'fruit', 'env'
productFlavors {
pear {
dimension 'fruit'
}
banana {
dimension 'fruit'
}
staging {
dimension 'env'
}
prod {
dimension 'env'
}
}
I would like to have these applicationId by flavor combination :
pearStaging : com.example.pear_staging (note the "_")
pearProd : com.example.pear
bananaStaging : com.example.banana_staging (note the "_")
bananaProd : com.example.banana
I have tried to use applicationIdSuffix :
productFlavors {
pear {
dimension 'fruit'
applicationIdSuffix 'pear'
}
banana {
dimension 'fruit'
applicationIdSuffix 'banana'
}
staging {
dimension 'env'
applicationIdSuffix '_staging'
}
prod {
dimension 'env'
}
}
but suffixes are separated with dot by default. So it's generate wrong applicationId, ex:
flavor pearStaging : com.example.pear._staging (note the "." before "_")
I saw answers on this thread :
How to set different applicationId for each flavor combination using flavorDimensions?
They talk about a workaround using mergedFlavor.setApplicationId(...) to override applicationId at the end. But this not working if I use in combination with google services gradle plugin.
Because during plugin process phase, I got this error :
* What went wrong:
Execution failed for task ':app:processPearStagingDebugGoogleServices'.
> No matching client found for package name 'com.example'
As you see, it use default applicationId/package name, not the appId overrided in android.applicationVariants.all phase.
So there is a better way to defined my applicationId per flavor combination that works with google services task ? (I need to keep these applicationId with "_", can't change it).
It is not possible with the current way that google services gradle plugin works. Maybe there's a way to feedback to Google about that, but meanwhile, the only way to achieve the application IDs with "_" is to rename the application ID after the apk is built. So, the flavour-specific application ID would be built with "." separators first, then rename the application ID after the apk is built.
This could be done with the standard procedure of using apktool to open the apk, change the application ID to what you need, then repackage with apktool, zipalign, re-sign, etc. If it may be too tedious, there are GitHub projects that attempt to do the same, but they may not work on all apks.
For example:
https://github.com/testwhat/PackageRenamer
https://github.com/sjitech/ApkRename
How should I increase my version number in an android project, as a step of build pipeline app center deployment? Does the Azure DevOps has a version manager plugin, or should I create a version.properties file and edit, commit, push into the current branch?
Build pipeline:
This can be done more clean with out using the properties file and then replacing that using a shell script.
In the top level build.gradle file, under the build scripts:
buildscript {
def getVersionCode = { ->
def code = project.hasProperty('versionCode') ? versionCode.toInteger() : -1
println "VersionCode is set to $code"
return code
}
def getVersionName = { ->
def name = project.hasProperty('versionName') ? versionName : "1.0"
println "VersionName is set to $name"
return name
}
ext{
versionCode = getVersionCode()
versionName = getVersionName()
}
}
In your module specific gradle file :
defaultConfig {
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
In your Devops pipeline for the gradle build task, just pass on the options like so:
-PversionName=$(Build.BuildNumber) -PversionCode=$(Build.BuildId)
Unfortunately is no out of the box support, but you can find here a good tutorial:
Install Colin's ALM Corner Build & Release Tools that include Version Assemblies task.
In the Android manifest the name and code should look like this:
android:versionCode="1" android:versionName="1.0.0"
Add the “Version Assemblies” task TWICE, once for the version name and once for the version code.
Once added, we will bump the name.
First insert the following (with examples):
Source Path: src/MobileApps/MyDriving/MyDriving.Android/Properties
File Pattern: AndroidManifest.xml
Build Regex Pattern: (?:\d+.\d+.\d+.)(\d+)
Under Advanced:
Build Regex Group Index: 0
Regex Replace Pattern: versionName=“\d+.\d+.\d+
Prefix for Replacements: versionName=”
What this will do is update the version name to the Build number format found under “General”, which mine is set to 1.0.0$(rev:.r)
Now for the next one, which is the version code:
Source Path: src/MobileApps/MyDriving/MyDriving.Android/Properties
File Pattern: AndroidManifest.xml
Build Regex Pattern: (?:\d+.\d+.\d+.)(\d+)
Under Advanced:
Build Regex Group Index: 1
Regex Replace Pattern: versionCode=“\d+
Prefix for Replacements: versionCode\
And just like that you are good to go. This will simply update it with the current version revision :)
There is an existing task called
Mobile App Tasks for iOS and Android in the marketplace which was developed by James Montemagno
You can find the step-by-step instruction in the github
He has developed this task mainly to address this kind of versioning in both android/IOS Apps.
The best solution for me was make a version.properties file to track versioning and then modify it during the pipeline build process (shell script). The others are bad especially for custom versioning.
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.
Say I have a production version com.android.xyz and this is production
then I am developing something and i want to load both this version and the production version on my phone so it's side by side. I know I can create a new package like com.android.abc and then I would have a second app which is basically a clone of com.android.xyz.
Thoughts?
Thanks in advance,
Reid
IF you are using Android Studio with Gradle, there is an easy way to do this. I still keep the the same packageName in AndroidManifest.xml (at least current gradle needs this duplicate definition)
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
package="com.android.xyz">
build.gradle
def devBuildName = "dev"
def testBuildName = "test"
android {
defaultConfig {
versionCode 70
versionName "2.2.3"
minSdkVersion 10
targetSdkVersion 19
packageName "com.android.xyz"
}
buildTypes {
debug {
packageNameSuffix "."+devBuildName
versionNameSuffix "-"+devBuildName.toUpperCase()
}
test.initWith(buildTypes.debug)
test {
packageNameSuffix "."+testBuildName
versionNameSuffix "-"+testBuildName.toUpperCase()
}
}
}
You can look at my full dev/release example at github.
You need to change the package name. IMO the easiest way to do this is by writing a perl/python script to iterate through the files and change the package name based on the build type. Or run a C style macro preprocessor over the files first.
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.