Now I am using android productFlavors to package app in flutter, this is my command:
~/apps/flutter/bin/flutter build apk --release --flavor prod -t lib/main_pro.dart --no-sound-null-safety
but the output name is always app-prod-release.apk:
$ ~/apps/flutter/bin/flutter build apk --release --flavor prod -t lib/main_pro.dart --no-sound-null-safety ‹ruby-2.7.2›
Changing current working directory to: /Users/dolphin/source/cruise-open
Building without sound null safety
For more information see https://dart.dev/null-safety/unsound-null-safety
Running Gradle task 'assembleProdRelease'...
Running Gradle task 'assembleProdRelease'... Done 7.1s
✓ Built build/app/outputs/flutter-apk/app-prod-release.apk (23.7MB).
(base)
this is my android/app/build.gradle gradle config:
flavorDimensions 'app'
productFlavors {
prod {
dimension 'app'
resValue "string", "app_name", "Cruise"
manifestPlaceholders = [
"APP_NAME" : "cruise-production"
]
}
}
now I want the package name likecruise-prouction-release.apk, not app-prod-release.apk. what should I do to change the defualt package name? I have tries this to change the output package name to releaseApkName.apk:
buildTypes {
release {
signingConfig signingConfigs.debug
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
println("releaseApkName")
output.outputFileName = "releaseApkName.apk"
}
}
}
}
but it seems not worked. This is my full config now:
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.earth.dolphin"
minSdkVersion 18
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
signingConfig signingConfigs.debug
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = "a.apk"
}
}
}
}
flavorDimensions 'app'
productFlavors {
dev {
dimension 'app'
resValue "string", "app_name", "Cruise-dev"
applicationIdSuffix '.dev'
}
stage {
dimension 'app'
resValue "string", "app_name", "Cruise-stage"
applicationIdSuffix '.stage'
}
prod {
dimension 'app'
resValue "string", "app_name", "Cruise"
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
the gradle version is 5.6.2. This is the output still using default name:
finally I am using this script, it works:
buildTypes {
release {
signingConfig signingConfigs.debug
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
def buildType = variant.buildType.name
println("buildType=" + buildType)
if (buildType != "debug") {
def projectRootDir = "$rootDir"
def outputFileDir = new File(projectRootDir + File.separator, "apk")
println("outputFileDir=" + outputFileDir)
def productFlavorsName = productFlavors.name.toString()
def oldApkFlavorsName = productFlavorsName.replace("[", "").trim()
def newApkFlavorsName = oldApkFlavorsName.replace("]", "").trim()
println("newApkFlavorsName=" + newApkFlavorsName)
def apkFlavorsNameDir = new File(outputFileDir, newApkFlavorsName)
println("apkFlavorsNameDir=" + apkFlavorsNameDir)
// variant.getPackageApplicationProvider().get().outputDirectory = apkFlavorsNameDir
def appName
if (productFlavorsName.contains("dev")) {
appName = "cruise-dev"
} else if (productFlavorsName.contains("test")) {
appName = "cruise-beta"
} else if (productFlavorsName.contains("prod")) {
appName = "cruise-release"
}else{
appName = "cruise-beta"
}
def releaseApkName = "" + appName + "-" + defaultConfig.versionName + ".apk"
output.outputFileName = releaseApkName
}
}
}
}
}
the package output path is:
/Users/dolphin/source/cruise-open/build/app/outputs/apk/prod/release
look like this:
I have already installed the NDK version '21.0.6113669' but still while I am trying to Sync Project with Gradle Files , getting the following error:
NDK not configured. Download it with SDK manager. Preferred NDK version is '21.0.6113669'.
Update NDK version to 21.0.6113669 and sync project
Kindly find below my build.gradle
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
plugins {
id "com.android.application"
}
android {
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion '21.0.6113669'
dependencies {
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.drawerlayout:drawerlayout:1.1.0"
implementation project(":terminal-view")
}
defaultConfig {
applicationId "com.termux"
minSdkVersion project.properties.minSdkVersion.toInteger()
targetSdkVersion project.properties.targetSdkVersion.toInteger()
versionCode 101
versionName "0.101"
externalNativeBuild {
ndkBuild {
cFlags "-std=c11", "-Wall", "-Wextra", "-Werror", "-Os", "-fno-stack-protector", "-Wl,--gc-sections"
}
}
ndk {
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
}
signingConfigs {
debug {
storeFile file('dev_keystore.jks')
keyAlias 'alias'
storePassword 'xrj45yWGLbsO7W0v'
keyPassword 'xrj45yWGLbsO7W0v'
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.debug
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
ndkBuild {
path "src/main/cpp/Android.mk"
}
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
buildToolsVersion '27.0.3'
}
dependencies {
testImplementation 'junit:junit:4.13'
testImplementation 'org.robolectric:robolectric:4.3.1'
}
task versionName {
doLast {
print android.defaultConfig.versionName
}
}
def downloadBootstrap(String arch, String expectedChecksum, int version) {
def digest = java.security.MessageDigest.getInstance("SHA-256")
def localUrl = "src/main/cpp/bootstrap-" + arch + ".zip"
def file = new File(projectDir, localUrl)
if (file.exists()) {
def buffer = new byte[8192]
def input = new FileInputStream(file)
while (true) {
def readBytes = input.read(buffer)
if (readBytes < 0) break
digest.update(buffer, 0, readBytes)
}
def checksum = new BigInteger(1, digest.digest()).toString(16)
if (checksum == expectedChecksum) {
return
} else {
logger.quiet("Deleting old local file with wrong hash: " + localUrl)
file.delete()
}
}
def remoteUrl = "https://bintray.com/termux/bootstrap/download_file?file_path=bootstrap-" + arch + "-v" + version + ".zip"
logger.quiet("Downloading " + remoteUrl + " ...")
file.parentFile.mkdirs()
def out = new BufferedOutputStream(new FileOutputStream(file))
def connection = new URL(remoteUrl).openConnection()
connection.setInstanceFollowRedirects(true)
def digestStream = new java.security.DigestInputStream(connection.inputStream, digest)
out << digestStream
out.close()
def checksum = new BigInteger(1, digest.digest()).toString(16)
if (checksum != expectedChecksum) {
file.delete()
//throw new GradleException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
throw new FileNotFoundException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
}
}
clean {
doLast {
def tree = fileTree(new File(projectDir, 'src/main/cpp'))
tree.include 'bootstrap-*.zip'
tree.each { it.delete() }
}
}
task downloadBootstraps(){
doLast {
def version = 30
downloadBootstrap("aarch64", "7a90034285c614d23fa450547a5e2aec77d4242c9891ad662bf0c6fd3bd7ef4e", version)
downloadBootstrap("arm", "f030869ce9a43f84d88560d7ac5153ee4f7e517bca0b37ab01df3e1acba0fe37", version)
downloadBootstrap("i686", "1ea9b63f21602231140d58a5545cfbc6bc2ded56ef2b3c31cba2759d913eef00", version)
downloadBootstrap("x86_64", "a50eb8a4dd02b7898bbd4a9653a25c14b56c1737409ce7f64110fd33c2c69382", version)
}
}
//buildscript {
// dependencies {
// classpath 'com.android.tools.build:gradle:4.0.0'
// }
//}
afterEvaluate {
android.applicationVariants.all { variant ->
variant.javaCompileProvider.get().dependsOn(downloadBootstraps)
}
}
I have removed .gradle folder from my laptop and reinstalled and also tried the option Invalidate Caches/Restart option from Android Studio but still the issue remains unresolved.
Any suggestions will be welcome.
this is build.gradle in Android directory! you must add
android {
ndkVersion '21.3.6528147'
...
to build.gradle in Android/app and remove ndk version ... from Android/build.gradle
my simple build.gradle in Android/app code :
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 30
ndkVersion '21.0.6113669'
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
checkReleaseBuilds false
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.test.test"
minSdkVersion 16
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
Download Ndk from " https://developer.android.com/ndk " and Unzip it to a location, Add it's path in local.properties file as like:
ndk.dir=C:\Users\AppData\android-ndk-r23b
And change the version of ndk in build.gradle file
android {
ndkVersion '23.1.7779620'
...
Syc Now and build your app
I have successfully incremented version code. But I only want to increment it while I do generate signed apk from menu Build -> Generate signed APK. Following is my gradle code.
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def code = versionProps['build.version'].toInteger() + 1
versionProps['build.version']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
applicationId "com.test"
multiDexEnabled true
versionCode code
versionName "1.1"
minSdkVersion 18
targetSdkVersion 23
}
}
else {
throw new GradleException("Could not read version.properties!")
}
buildTypes {
release {
//minifyEnabled false
//proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
debuggable true
}
}
dexOptions {
incremental true
javaMaxHeapSize "4g"
preDexLibraries = false
}}
And my version.properties file contains following info:
Minor=7
Branch=4
Major=10
build.version=73
I am able to do it by hooking up my code on assembleRelease gradle task. Got help from Tim's blog. Following is the code-
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
def Properties versionProps = loadVersionFile()
defaultConfig {
applicationId "com.test"
multiDexEnabled true
versionCode getCode(versionProps)
versionName getName(versionProps)
minSdkVersion 18
targetSdkVersion 23
}
signingConfigs {
release {
storeFile file(".../keys.jks")
storePassword "..."
keyAlias "..."
keyPassword "..."
}
}
buildTypes {
release {
signingConfig signingConfigs.release
//minifyEnabled false
//proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
debuggable true
}
}
dexOptions {
...
}
}
def loadVersionFile() {
def versionPropsFile = file('version.properties')
def Properties versionProps
if (versionPropsFile.canRead()) {
versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
} else {
throw new GradleException("Could not read version.properties!")
}
return versionProps}
def getCode(Properties versionProps) {
return versionProps['build.version'].toInteger()}
def getName(Properties versionProps) {
return versionProps['product.version']}
assembleRelease << {
def versionPropsFile = file('version.properties')
def code
def Properties versionProps
if (versionPropsFile.canRead()) {
versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
code = versionProps['build.version'].toInteger() + 1
} else {
throw new GradleException("Could not read version.properties!")
}
versionProps['build.version'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
project.android.defaultConfig.versionCode code}
allprojects {
repositories {
jcenter()
mavenCentral()
flatDir {
dirs 'libs'
}
maven {
...
}
}}
dependencies {...}
apply plugin: 'com.google.gms.google-services'
To find out where you have to place the gradle.properties
Extract the whole signing config
First option is, to extract the whole signing config to a separate user file. Create a new property in your gradle.properties:
MyProject.signing=/home/username/.signing/myproject
MyProject doesn’t need to match any application names or so, you can in fact name the property whatever you like. Also if you’re on windows use \ instead of /.
Place your keystore at /home/username/.signing/myproject.keystore.
Now create a file name myproject.gradle in /home/username/.signing (create the folder if necessary). This file will contain your signing config, that should be used to sign the package. This could look like the following:
android {
signingConfigs {
release {
storeFile file(project.property("MyProject.signing") + ".keystore")
storePassword "mypassword"
keyAlias "KeyAlias"
keyPassword "mypassword"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
Now its time to configure the actual build.gradle file in the project you want to use this signing config. Just add the following lines to it:
if(project.hasProperty("MyProject.signing")
&& new File(project.property("MyProject.signing") + ".gradle").exists()) {
apply from: project.property("MyProject.signing") + ".gradle";
}
Only extract some variables from file
project.ext {
uploadRepo = 'http://....'
uploadUser = 'myusername'
uploadPass = 'mypass'
}
Now make sure you only use the variables if they are available by putting the configuration in the if after you loaded the file. So your build.gradle could look like that:
if(project.hasProperty("MyProject.signing")
&& new File(project.property("MyProject.signing") + ".gradle").exists()) {
apply from: project.property("MyProject.signing") + ".gradle";
// Configure stuff that relies on these variables
uploadArchives {
repositories.mavenDeployer {
repository(url: uploadRepo) {
authentication(userName: uploadUser, password: uploadPass)
}
}
// .. whatever else you need ...
}
}
Only extract some strings from file
Again add a path to your gradle.properties (let’s do it a full path this time):
MyProject.properties=/home/username/.signing/myproject.properties
if(project.hasProperty("MyProject.properties")
&& new File(project.property("MyProject.properties")).exists()) {
Properties props = new Properties()
props.load(new FileInputStream(file(project.property("MyProject.properties"))))
android {
signingConfigs {
release {
storeFile file(props['keystore'])
storePassword props['keystore.password']
// ...
}
}
}
}
Just generate a plain properties file at /home/username/.signing/myproject.properties:
keystore=/path/to/my/keystore
keystore.password=mypassword
I am trying to create a BuildConfingField in my gradle script here my code
def VERSION_NAME = "3.1.0b"
def VERSION=VERSION_NAME+"-"+getDate();
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 10
targetSdkVersion 23
setProperty("archivesBaseName",POM_ARTIFACT_ID +"-"+VERSION_NAME+"-"+ getDate())
}
buildTypes {
release {
minifyEnabled false // non usare MAI proguard a meno di non aver ispezionato bene il codice!!
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "VERSION", VERSION
}
debug {
minifyEnabled false
buildConfigField "String", "VERSION",VERSION
}
}
}
def getDate() {
def date = new Date()
def formattedDate = date.format('yyMMddHHmm') //'yyyyMMddHHmmss'
return formattedDate
}
What I get is:
public static final String VERSION = 3.1.0b-1605021144;
This brings compilation error.
Anyone can help on getting the string defined correctly?
Use "\"${VERSION}\"" or '"'+VERSION+'"'.
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.