Gradle Autoincrement and Rename APK I/O Error - android

I'm trying to do an auto increment for the build number in Android Studio. Followed this link, and it worksfine.
Now I want to rename the apk using the versionName. I also did that successfully, as I can see in my app\build\outputs\apk directory, that the file is there.
The problem The generated apk and the part where Android Studio you see the "local path" don't have the same file name.
The generated apk's name: MyAppsName-v1.0-64-debug.apk
The "local path" it's looking for: ..\app\build\outputs\apk\MyAppsName-v1.0-60-debug.apk
So it makes sense to see an error saying "Local path doesn't exist." Because the "MyAppsName-v1.0-60-debug.apk" does not exist.
Here's the snippet of my build.gradle:
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def value = 0
def runTasks = gradle.startParameter.taskNames
if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
value = 1;
}
def versionMajor = 1
def versionMinor = 0
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
def version_Code = versionProps['VERSION_CODE'].toInteger() + value
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps['VERSION_CODE'] = version_Code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode version_Code
versionName "v${versionMajor}.${versionMinor}-${versionBuild}"
minSdkVersion 15
targetSdkVersion 21
}
archivesBaseName = "MyAppsName" + "-" + defaultConfig.versionName;
} else {
throw new GradleException("Could not read version.properties!")
}

Related

Execute a Gradle Task (Commit changes to git) everytime I run my Android app

I am using a modified version of this.
This is my code:
def mAppName = "App"
def mVersionName = "0.0." //Increase this version manually
//https://stackoverflow.com/a/23265711
def versionPropsFile = file('version.properties')
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
//Initial version is 0.0.1 (0)
//With version code 1
versionProps['VERSION_PATCH'] = "1"
//Only gets auto incremented on release. So start at 1 (debug)
versionProps['VERSION_BUILD'] = "0"
versionProps['VERSION_CODE'] = "0" //Starts at zero gets auto incremented
versionProps['VERSION_NAME'] = mVersionName
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
def value = 0
if ('assembleRelease' in runTasks) {
//todo check task name, before building release builds
value = 1
}
def mFileName = ""
def mVersionNameComplete = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_CODE'] = (versionProps['VERSION_CODE'].toInteger() + 1).toString()
if (versionProps['VERSION_NAME'].equals(mVersionName)) {
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString()
} else {
versionProps['VERSION_PATCH'] = "0"
versionProps['VERSION_BUILD'] = "0"
versionProps['VERSION_NAME'] = mVersionName
}
mVersionNameComplete = "${versionProps['VERSION_NAME']}${versionProps['VERSION_PATCH']}"
mFileName = "${mAppName}-${mVersionNameComplete}.apk"
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
applicationId "com.test.app"
versionCode versionProps['VERSION_CODE'].toInteger()
versionName "${mVersionNameComplete} Build: ${versionProps['VERSION_BUILD']}"
vectorDrawables.useSupportLibrary = false
minSdkVersion 21
targetSdkVersion 30
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "en", "de" // And any other languages you support
//Required when setting minSdkVersion to 20 or lower
//multiDexEnabled true
}
//-------------------------------------------------------------------------------------------
file("../git_commit.bat").text = """
#echo off
git add .
git commit -m "Auto commit. Version name: ${mVersionNameComplete} Build: ${versionProps['VERSION_BUILD']}, Version code: ${versionProps['VERSION_CODE']}"
git push
"""
//-------------------------------------------------------------------------------------------
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
task autoCommit(type: Exec) {
workingDir '../.'
commandLine 'cmd', '/c', 'git_commit.bat'
}
if ('assembleRelease' in runTasks) {
applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
outputFileName = mFileName
}
}
}
}
task copyApkFiles(type: Copy) {
from 'build/outputs/apk/release'
into '../apk'
include mFileName
}
afterEvaluate {
assembleRelease.doLast {
tasks.copyApkFiles.execute()
}
}
//build.finalizedBy(autoCommit)
What I want is that
task autoCommit(type: Exec) {
workingDir '../.'
commandLine 'cmd', '/c', 'git_commit.bat'
}
This task gets automatically executed on every compilation. Sadly build.finalizedBy(autoCommit) does not work. What is the trick here?
(I managed to execute the task on every build using the 'Run/Debug configuration -> Before launch' section. But doing so executes the gradle part that increases my version number twice. That way my commit is automatically pushed but has the version number of the compilation AFTER the current one)

How can i get the correct gradle.startParameter.taskNames for an APK Build in Android Studio

I want to increment the variable 'value' after clicking Build -> Build Bundles/APKs -> Build APK in Android Studio.
I modified my build.gradle like this:
def versionPropsFile = file('../gradle.properties')
def value = 0
def runTasks = gradle.startParameter.taskNames
Properties versionProps = new Properties()
...
if ('assemble' in runTasks || 'debug' in runTasks || 'release' in runTasks) {
value = 1
}
But i never enter the if branch even though i check the conditions for debug and release too.
My goal would be to increment the variable only if i build a new APK.
Thanks in advance.
When i added following in build.gradle; it goes into 'if'
defaultConfig {
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
def value = 0
def runTasks = gradle.startParameter.taskNames
if(runTasks.toString().contains('assemble') || runTasks.toString().contains('debug') || runTasks.toString().contains('release')) {
println "Yes all"
}
}

Increase versionCode by one Automatically after executing packageReleaseJar

I have following in android tag of build.gradle in order to increase versionCode:
apply plugin: 'com.android.library'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
List<String> runTasks = gradle.startParameter.getTaskNames();
def value = 0
for (String item : runTasks)
if (item.contains("packageReleaseJar")) {
value = 1;
}
def code = versionProps['VERSION_CODE'].toInteger() + value
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
minSdkVersion 8
targetSdkVersion 22
versionCode code
versionName version
testApplicationId 'se.android.instrumenttest'
testInstrumentationRunner 'se.android.Runner'
printf("\n--------" + "VERSION DATA--------"
+ "\n" + "- CODE: " + versionCode + "\n" +
"- NAME: " + versionName + "\n----------------------------\n")
}
} else {
throw new GradleException("Could not read version.properties!")
}
The idea taken from commonsguy sample.
I expect that when I execute packageReleaseJar task using Gradle wrapper, versionCode increased by one. But it is not working as expected.
I guess it could be related to generateReleaseBuildConfig task.
What could be the reason and what is solution for that?
Addenda
def getVersionCode() {
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def code = versionProps['VERSION_CODE'].toInteger()
} else {
throw new GradleException("Could not read version.properties!")
}
return code
}
This method is not working as expected, but when use the logic of method in the android tag, problem will be solved:
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def code = versionProps['VERSION_CODE'].toInteger()
defaultConfig {
minSdkVersion 8
targetSdkVersion 22
versionCode code
versionName version
testApplicationId 'se.android.instrumenttest'
testInstrumentationRunner 'se.android.Runner'
printf("\n--------" + "VERSION DATA--------\n" +
"- CODE: " + versionCode + "\n" +
"- NAME: " + versionName +
"\n----------------------------\n")
}
} else {
throw new GradleException("Could not read version.properties!")
}

Auto increment versioncode only on releases

Currently I'm trying to improve our buildscript with auto incrementing the versioncode so our QA team has got a clue what build they are testing and can log against a specific versioncode. We have got 3 productFlavors (staging, qa, production) and 2 signing configs (debug, release).
I looked into different solutions:
How to autoincrement versionCode in Android Gradle
How to autoincrement versionCode in Android Gradle
Autoincrement VersionCode with gradle extra properties
Based on those answers I've built a versioncode incrementor using a version.properties file.
Now the problem arises that for EVERY productFlavor and SigningConfig combination (+ the gradle sync in android studio) a new versioncode is generated. I want the versioncode to increment whenever I hit the play button to create a qaRelease build. So our buildcycle would be:
development (never change the versioncode)
qual (Update the versioncode)
production (never change the versioncode)
How I solved it:
I created a file version.properties in the root of my android project and added the versioncode in it.
Then I created method called getCurrentVersionCode() in my build.gradle file that reads the current versioncode.
Code:
def getCurrentVersionCode() {
def versionPropsFile = file('version.properties')
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
return versionProps['version_code'].toInteger()
}
I also created a method to generate a new code:
Code:
// http://stackoverflow.com/questions/30523393/auto-increment-versioncode-only-on-releases
//
def setUpdatedVersionCode() {
def versionPropsFile = file('version.properties')
def Properties versionProps = new Properties()
def code = getCurrentVersionCode() + 1
versionProps['version_code'] = code.toString()
versionProps['version_name'] = generateVersionName()
versionProps.store(versionPropsFile.newWriter(), null)
}
and then I created a task that triggers on a QA build.
Code:
task('increaseVersionCode') << {
setUpdatedVersionCode()
}
tasks.whenTaskAdded { task ->
if (task.name == 'assembleQaRelease') {
task.dependsOn 'increaseVersionCode'
}
}
That way it saves the versioncode in a separate file so I don't need to edit my build.gradle.
You could try something like that
import java.util.regex.Pattern
task('increaseVersionCode') << {
... // You could code in your increment system, for eg
// Using build.gradle (recommended)
def buildFile = file("build.gradle")
def pattern = Pattern.compile("versionCode\\s+(\\d+)")
def manifestText = buildFile.getText()
def matcher = pattern.matcher(manifestText)
matcher.find()
def versionCode = Integer.parseInt(matcher.group(1))
def manifestContent = matcher.replaceAll("versionCode " + ++versionCode)
buildFile.write(manifestContent)
// Using manifest
def manifestFile = file('AndroidManifest.xml')
def matcher = Pattern.compile('versionCode=\"(\\d+)\"')
.matcher(manifestFile.getText())
matcher.find()
def manifestContent = matcher.replaceAll('versionCode=\"' +
++Integer.parseInt(matcher.group(1)) + '\"')
manifestFile.write(manifestContent)
}
tasks.whenTaskAdded { task ->
if (task.name == 'assembleQaRelease') {
task.dependsOn 'increaseVersionCode'
}
}
You can adapt the 'assembleQaRelease' to increment version code to the wanted task.

Autoincrement VersionCode with gradle extra properties

I'm building an Android app with gradle. Until now I used the Manifest file to increase the versionCode, but I would like to read the versionCode from an external file and depending if it is the release flavor or the debug flavor increase the versionCode. I tried the extra properties, but you can't save them, which means that next time I build it I'm getting the same versionCode.
Any help would be very much appreciated!
project.ext{
devVersionCode = 13
releaseVersionCode = 1
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile project(':Cropper')
compile "com.android.support:appcompat-v7:18.0.+"
compile "com.android.support:support-v4:18.0.+"
compile fileTree(dir: 'libs', include: '*.jar')
}
def getReleaseVersionCode() {
def version = project.releaseVersionCode + 1
project.releaseVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getDevVersionCode() {
def version = project.devVersionCode + 1
project.devVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getLastVersioName(versionCode) {
return "0.0." + versionCode
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 9
targetSdkVersion 19
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
buildTypes {
release {
runProguard true
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFile 'proguard.cfg'
debuggable false
signingConfig null
zipAlign false
}
debug {
versionNameSuffix "-DEBUG"
}
}
productFlavors {
dev {
packageName = 'com.swisscom.docsafe.debug'
versionCode getDevVersionCode()
versionName getLastVersioName(project.devVersionCode)
}
prod {
packageName = 'com.swisscom.docsafe'
versionCode getReleaseVersionCode()
versionName getLastVersioName(project.releaseVersionCode)
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
I would like to read the versionCode from an external file
I am sure that there are any number of possible solutions; here is one:
android {
compileSdkVersion 18
buildToolsVersion "18.1.0"
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!")
}
// rest of android block goes here
}
This code expects an existing version.properties file, which you would create by hand before the first build to have VERSION_CODE=8.
This code simply bumps the version code on each build -- you would need to extend the technique to handle your per-flavor version code.
You can see the Versioning sample project that demonstrates this code.
Here comes a modernization of my previous answer which can be seen below. This one is running with Gradle 4.4 and Android Studio 3.1.1.
What this script does:
Creates a version.properties file if none exists (up vote Paul Cantrell's answer below, which is where I got the idea from if you like this answer)
For each build, debug release or any time you press the run button in Android Studio the VERSION_BUILD number increases.
Every time you assemble a release your Android versionCode for the play store increases and your patch number increases.
Bonus: After the build is done copies your apk to projectDir/apk to make it more accessible.
This script will create a version number which looks like v1.3.4 (123) and build an apk file like AppName-v1.3.4.apk.
Major version ⌄ ⌄ Build version
v1.3.4 (123)
Minor version ⌃|⌃ Patch version
Major version: Has to be changed manually for bigger changes.
Minor version: Has to be changed manually for slightly less big changes.
Patch version: Increases when running gradle assembleRelease
Build version: Increases every build
Version Number: Same as Patch version, this is for the version code which Play Store needs to have increased for each new apk upload.
Just change the content in the comments labeled 1 - 3 below and the script should do the rest. :)
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['VERSION_PATCH'] = "0"
versionProps['VERSION_NUMBER'] = "0"
versionProps['VERSION_BUILD'] = "-1" // I set it to minus one so the first build is 0 which isn't super important.
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
if ('assembleRelease' in runTasks) {
value = 1
}
def mVersionName = ""
def mFileName = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps['VERSION_NUMBER'] = (versionProps['VERSION_NUMBER'].toInteger() + value).toString()
versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString()
versionProps.store(versionPropsFile.newWriter(), null)
// 1: change major and minor version here
mVersionName = "v1.0.${versionProps['VERSION_PATCH']}"
// 2: change AppName for your app name
mFileName = "AppName-${mVersionName}.apk"
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
applicationId "com.example.appname" // 3: change to your package name
versionCode versionProps['VERSION_NUMBER'].toInteger()
versionName "${mVersionName} Build: ${versionProps['VERSION_BUILD']}"
}
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
if ('assembleRelease' in runTasks) {
applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
outputFileName = mFileName
}
}
}
}
task copyApkFiles(type: Copy){
from 'build/outputs/apk/release'
into '../apk'
include mFileName
}
afterEvaluate {
assembleRelease.doLast {
tasks.copyApkFiles.execute()
}
}
signingConfigs {
...
}
buildTypes {
...
}
}
====================================================
INITIAL ANSWER:
I want the versionName to increase automatically as well. So this is just an addition to the answer by CommonsWare which worked perfectly for me. This is what works for me
defaultConfig {
versionCode code
versionName "1.1." + code
minSdkVersion 14
targetSdkVersion 18
}
EDIT:
As I am a bit lazy I want my versioning to work as automatically as possible. What I want is to have a Build Version that increases with each build, while the Version Number and Version Name only increases when I make a release build.
This is what I have been using for the past year, the basics are from CommonsWare's answer and my previous answer, plus some more. This results in the following versioning:
Version Name: 1.0.5 (123) --> Major.Minor.Patch (Build), Major and Minor are changed manually.
In build.gradle:
...
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def value = 0
def runTasks = gradle.startParameter.taskNames
if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
value = 1;
}
def versionMajor = 1
def versionMinor = 0
def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
versionProps['VERSION_PATCH'] = versionPatch.toString()
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps['VERSION_NUMBER'] = versionNumber.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode versionNumber
versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild}) Release"
minSdkVersion 14
targetSdkVersion 23
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def fileNaming = "apk/RELEASES"
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
output.outputFile = new File(getProject().getRootDir(), "${fileNaming}-${versionMajor}.${versionMinor}.${versionPatch}-${outputFile.name}")
}
}
}
}
} else {
throw new GradleException("Could not read version.properties!")
}
...
}
...
Patch and versionCode is increased if you assemble your project through the terminal with 'assemble', 'assembleRelease' or 'aR' which creates a new folder in your project root called apk/RELEASE so you don't have to look through build/outputs/more/more/more to find your apk.
Your version properties would need to look like this:
VERSION_NUMBER=1
VERSION_BUILD=645
VERSION_PATCH=1
Obviously start with 0. :)
A slightly tightened-up version of CommonsWare's excellent answer creates the version file if it doesn't exist:
def Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if(versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode code
versionName "1.1"
minSdkVersion 14
targetSdkVersion 18
}
I looked at a few options to do this, and ultimately decided it was simpler to just use the current time for the versionCode instead of trying to automatically increment the versionCode and check it into my revision control system.
Add the following to your build.gradle:
/**
* Use the number of seconds/10 since Jan 1 2016 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
def vcode = (int)(((new Date().getTime()/1000) - 1451606400) / 10)
android {
defaultConfig {
...
versionCode vcode
}
}
However, if you expect to upload builds beyond year 2696, you may want to use a different solution.
Another way of getting a versionCode automatically is setting versionCode to the number of commits in the checked out git branch. It accomplishes following objectives:
versionCode is generated automatically and consistently on any machine (including a Continuous Integration and/or Continuous Deployment server).
App with this versionCode is submittable to GooglePlay.
Doesn't rely on any files outside of repo.
Doesn't push anything to the repo
Can be manually overridden, if needed
Using gradle-git library to accomplish the above objectives. Add code below to your build.gradle file the /app directory:
import org.ajoberstar.grgit.Grgit
repositories {
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.ajoberstar:grgit:1.5.0'
}
}
android {
/*
if you need a build with a custom version, just add it here, but don't commit to repo,
unless you'd like to disable versionCode to be the number of commits in the current branch.
ex. project.ext.set("versionCodeManualOverride", 123)
*/
project.ext.set("versionCodeManualOverride", null)
defaultConfig {
versionCode getCustomVersionCode()
}
}
def getCustomVersionCode() {
if (project.versionCodeManualOverride != null) {
return project.versionCodeManualOverride
}
// current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
// above.
ext.repo = Grgit.open(project.file('..'))
// should result in the same value as running
// git rev-list <checked out branch name> | wc -l
def numOfCommits = ext.repo.log().size()
return numOfCommits
}
NOTE: For this method to work, it's best to only deploy to Google Play Store from the same branch (ex. master).
Recently I was working on a gradle plugin for Android that makes generating versionCode and versionName automatically. there are lots of customization. here you can find more info about it
https://github.com/moallemi/gradle-advanced-build-version
Create new file inside <yourProjectLocation>/app/version.properties
MAJOR=0
MINOR=0
PATCH=1
VERSION_CODE=1
Add following lines in build.gradle (Module file) :
android {
// other properties....
// add following lines...
def _versionCode=0
def _major=0
def _minor=0
def _patch=0
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
_patch = versionProps['PATCH'].toInteger() + 1
_major = versionProps['MAJOR'].toInteger()
_minor = versionProps['MINOR'].toInteger()
_versionCode= versionProps['VERSION_CODE'].toInteger()+1
if(_patch==100) {
_patch=0
_minor=_minor+1
}
if(_minor == 10){
_minor = 0
_major =_major + 1
}
versionProps['MAJOR']=_major.toString()
versionProps['MINOR']=_minor.toString()
versionProps['PATCH']=_patch.toString()
versionProps['VERSION_CODE']=_versionCode.toString()
versionProps.store(versionPropsFile.newWriter(), null)
}
else {
throw new GradleException("Could not read version.properties!")
}
def _versionName = "${_major}.${_minor}.${_patch}(${_versionCode})"
defaultConfig {
// other properties...
// change only these two lines
versionCode _versionCode
versionName _versionName
}
}
Output : 0.0.1(1)
Another option, for incrementing the versionCode and the versionName, is using a timestamp.
defaultConfig {
versionName "${getVersionNameTimestamp()}"
versionCode getVersionCodeTimestamp()
}
def getVersionNameTimestamp() {
return new Date().format('yy.MM.ddHHmm')
}
def getVersionCodeTimestamp() {
def date = new Date()
def formattedDate = date.format('yyMMddHHmm')
def code = formattedDate.toInteger()
println sprintf("VersionCode: %d", code)
return code
}
Starting on January,1 2022
formattedDate = date.format('yyMMddHHmm')
exceeds the capacity of Integers
To increment versionCode only in release version do it:
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
def versionPropsFile = file('version.properties')
def code = 1;
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
List<String> runTasks = gradle.startParameter.getTaskNames();
def value = 0
for (String item : runTasks)
if ( item.contains("assembleRelease")) {
value = 1;
}
code = Integer.parseInt(versionProps['VERSION_CODE']).intValue() + value
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
}
else {
throw new GradleException("Could not read version.properties!")
}
defaultConfig {
applicationId "com.pack"
minSdkVersion 14
targetSdkVersion 21
versionName "1.0."+ code
versionCode code
}
expects an existing c://YourProject/app/version.properties file, which you would create by hand before the first build to have VERSION_CODE=8
File
version.properties:
VERSION_CODE=8
Examples shown above don't work for different reasons
Here is my ready-to-use variant based on ideas from this article:
android {
compileSdkVersion 28
// https://stackoverflow.com/questions/21405457
def propsFile = file("version.properties")
// Default values would be used if no file exist or no value defined
def customAlias = "Alpha"
def customMajor = "0"
def customMinor = "1"
def customBuild = "1" // To be incremented on release
Properties props = new Properties()
if (propsFile .exists())
props.load(new FileInputStream(propsFile ))
if (props['ALIAS'] == null) props['ALIAS'] = customAlias else customAlias = props['ALIAS']
if (props['MAJOR'] == null) props['MAJOR'] = customMajor else customMajor = props['MAJOR']
if (props['MINOR'] == null) props['MINOR'] = customMinor else customMinor = props['MINOR']
if (props['BUILD'] == null) props['BUILD'] = customBuild else customBuild = props['BUILD']
if (gradle.startParameter.taskNames.join(",").contains('assembleRelease')) {
customBuild = "${customBuild.toInteger() + 1}"
props['BUILD'] = "" + customBuild
applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.outputFile != null && (output.outputFile.name == "app-release.apk"))
outputFileName = "app-${customMajor}-${customMinor}-${customBuild}.apk"
}
}
}
props.store(propsFile.newWriter(), "Incremental Build Version")
defaultConfig {
applicationId "org.example.app"
minSdkVersion 21
targetSdkVersion 28
versionCode customBuild.toInteger()
versionName "$customAlias $customMajor.$customMinor ($customBuild)"
...
}
...
}
Define versionName in AndroidManifest.xml
android:versionName="5.1.5"
Inside android{...} block in build.gradle of app level :
defaultConfig {
applicationId "com.example.autoincrement"
minSdkVersion 18
targetSdkVersion 23
multiDexEnabled true
def version = getIncrementationVersionName()
versionName version
}
Outside android{...} block in build.gradle of app level :
def getIncrementedVersionName() {
List<String> runTasks = gradle.startParameter.getTaskNames();
//find version name in manifest
def manifestFile = file('src/main/AndroidManifest.xml')
def matcher = Pattern.compile('versionName=\"(\\d+)\\.(\\d+)\\.(\\d+)\"').matcher(manifestFile.getText())
matcher.find()
//extract versionName parts
def firstPart = Integer.parseInt(matcher.group(1))
def secondPart = Integer.parseInt(matcher.group(2))
def thirdPart = Integer.parseInt(matcher.group(3))
//check is runTask release or not
// if release - increment version
for (String item : runTasks) {
if (item.contains("assemble") && item.contains("Release")) {
thirdPart++
if (thirdPart == 10) {
thirdPart = 0;
secondPart++
if (secondPart == 10) {
secondPart = 0;
firstPart++
}
}
}
}
def versionName = firstPart + "." + secondPart + "." + thirdPart
// update manifest
def manifestContent = matcher.replaceAll('versionName=\"' + versionName + '\"')
manifestFile.write(manifestContent)
println "incrementVersionName = " + versionName
return versionName
}
After create singed APK :
android:versionName="5.1.6"
Note : If your versionName different from my, you need change regex and extract parts logic.
Credits to
CommonsWare (Accepted Answer)
Paul Cantrell (Create file if it doesn't exist)
ahmad aghazadeh (Version name and code)
So I mashed all their ideas together and came up with this. This is the drag and drop solution to exactly what the first post asked.
It will automatically update the versionCode and versionName according to release status. Of course you can move the variables around to suite your needs.
def _versionCode=0
def versionPropsFile = file('version.properties')
def Properties versionProps = new Properties()
if(versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
def _patch = (versionProps['PATCH'] ?: "0").toInteger() + 1
def _major = (versionProps['MAJOR'] ?: "0").toInteger()
def _minor = (versionProps['MINOR'] ?: "0").toInteger()
List<String> runTasks = gradle.startParameter.getTaskNames();
def value = 0
for (String item : runTasks)
if ( item.contains("assembleRelease")) {
value = 1;
}
_versionCode = (versionProps['VERSION_CODE'] ?: "0").toInteger() + value
if(_patch==99)
{
_patch=0
_minor=_minor+1
}
if(_major==99){
_major=0
_major=_major+1
}
versionProps['MAJOR']=_major.toString()
versionProps['MINOR']=_minor.toString()
versionProps['PATCH']=_patch.toString()
versionProps['VERSION_CODE']=_versionCode.toString()
versionProps.store(versionPropsFile.newWriter(), null)
def _versionName = "${_major}.${_versionCode}.${_minor}.${_patch}"
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.yourhost.yourapp"
minSdkVersion 16
targetSdkVersion 24
versionCode _versionCode
versionName _versionName
}
There are two solutions I really like. The first depends on the Play Store and the other depends on Git.
Using the Play Store, you can increment the version code by looking at the highest available uploaded version code. The benefit of this solution is that an APK upload will never fail since your version code is always one higher than whatever is on the Play Store. The downside is that distributing your APK outside of the Play Store becomes more difficult. You can set this up using Gradle Play Publisher by following the quickstart guide and telling the plugin to resolve version codes automatically:
plugins {
id 'com.android.application'
id 'com.github.triplet.play' version 'x.x.x'
}
android {
...
}
play {
serviceAccountCredentials = file("your-credentials.json")
resolutionStrategy = "auto"
}
Using Git, you can increment the version code based on how many commits and tags your repository has. The benefit here is that your output is reproducible and doesn't depend on anything outside your repo. The downside is that you have to make a new commit or tag to bump your version code. You can set this up by adding the Version Master Gradle plugin:
plugins {
id 'com.android.application'
id 'com.supercilex.gradle.versions' version 'x.x.x'
}
android {
...
}
Instead of specifying the new version in a properties file, I created a Gradle task that can update the current versionName and versionCode automatically and also can get the new version string from command line (by passing arguments to the task with -P followed by <argName>=<argValue>).
app build.gradle.kts:
project.version = "1.2.3"
tasks.create("incrementVersion") {
group = "versioning"
description = "Increments the version to make the app ready for next release."
doLast {
var (major, minor, patch) = project.version.toString().split(".")
val mode = project.properties["mode"]?.toString()?.toLowerCaseAsciiOnly()
if (mode == "major") {
major = (major.toInt() + 1).toString()
minor = "0"
patch = "0"
} else if (mode == "minor") {
minor = (minor.toInt() + 1).toString()
patch = "0"
} else {
patch = (patch.toInt() + 1).toString()
}
var newVersion = "$major.$minor.$patch"
val overrideVersion = project.properties["overrideVersion"]?.toString()?.toLowerCaseAsciiOnly()
overrideVersion?.let { newVersion = it }
val newBuild = buildFile
.readText()
.replaceFirst(Regex("version = .+"), "version = \"$newVersion\"")
.replaceFirst(Regex("versionName = .+\""), "versionName = \"$newVersion\"")
.replaceFirst(Regex("versionCode = \\d+"), "versionCode = ${(android.defaultConfig.versionCode ?: 0) + 1}")
buildFile.writeText(newBuild)
}
}
Usage:
gradlew incrementVersion [-P[mode=major|minor|patch]|[overrideVersion=x.y.z]]
Examples:
gradlew :app:incrementVersion -Pmode=major
gradlew :app:incrementVersion -PoverrideVersion=4.5.6
The First Commented code will increment the number while each "Rebuild Project" and save the the value in the "Version Property" file.
The Second Commented code will generate new version name of APK file while "Build APKs".
android {
compileSdkVersion 28
buildToolsVersion "29.0.0"
//==========================START==================================
def Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if(versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
//===========================END===================================
defaultConfig {
applicationId "com.example.myapp"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "0.19"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
//=======================================START===============================================
android.applicationVariants.all { variant ->
variant.outputs.all {
def appName = "MyAppSampleName"
outputFileName = appName+"_v${variant.versionName}.${versionProps['VERSION_CODE']}.apk"
}
}
//=======================================END===============================================
}
}
}
in the Gradle 5.1.1 version on mac ive changed how the task names got retrieved, i althought tried to get build flavour / type from build but was to lazy to split the task name:
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def value = 0
def runTasks = gradle.getStartParameter().getTaskRequests().toString()
if (runTasks.contains('assemble') || runTasks.contains('assembleRelease') || runTasks.contains('aR')) {
value = 1
}
def versionMajor = 1
def versionMinor = 0
def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
versionProps['VERSION_PATCH'] = versionPatch.toString()
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps['VERSION_NUMBER'] = versionNumber.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
applicationId "de.evomotion.ms10"
minSdkVersion 21
targetSdkVersion 28
versionCode versionNumber
versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild})"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
signingConfig signingConfigs.debug
}
} else {
throw new GradleException("Could not read version.properties!")
}
code is from #just_user
this one
Using Gradle Task Graph we can check/switch build type.
The basic idea is to increment the versionCode on each build. On Each build a counter stored in the version.properties file. It will be keep updated on every new APK build and replace versionCode string in the build.gradle file with this incremented counter value.
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
def versionPropsFile = file('version.properties')
def versionBuild
/*Setting default value for versionBuild which is the last incremented value stored in the file */
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
versionBuild = versionProps['VERSION_BUILD'].toInteger()
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
/*Wrapping inside a method avoids auto incrementing on every gradle task run. Now it runs only when we build apk*/
ext.autoIncrementBuildNumber = {
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps.store(versionPropsFile.nminSdkVersion 14
targetSdkVersion 21
versionCode 1ewWriter(), null)
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 21
versionCode 1
versionName "1.0.0." + versionBuild
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// Hook to check if the release/debug task is among the tasks to be executed.
//Let's make use of it
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(assembleDebug)) { /* when run debug task */
autoIncrementBuildNumber()
} else if (taskGraph.hasTask(assembleRelease)) { /* when run release task */
autoIncrementBuildNumber()
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
}
Place the above script inside your build.gradle file of main module.

Categories

Resources