I have implemented Flavors in Android Studio and am now trying to place each Flavor in it's own directory, with its own unique name - sadly with a name different, in some cases, than the flavor name. :(
We have tools depending on it being the same, so if I can pull that off in gradle, all the better.
I have a sample that is using the version name suffix value as the directory name and that works. But what I would like to do is specify a value somewhere in the flavor config that would be used, however I find that when you set a property with the same name the last one wins - rather than each being used as specified in the config.
So, for example, lets say I have two Flavors : Jimbo and Randolph. However I want to place the Jimbo.apk in the "jimmy" folder and the Randolph.apk in the "randy" folder. How can I specify a value (directory) for each that will be picked up and used to store the generated APK? To add to the complexity I am renaming the APK current in the applicationVariants.all .
In the code below I am looking to somehow replace the versionNameSuffix with a variable I can somehow specify.
Here is what I have:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.mycompany.default"
minSdkVersion 14
targetSdkVersion 23
versionCode 11
versionName "1.0.11"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
versionNameSuffix 'randy'
}
Jimbo {
applicationId 'com.mycompany.jimmy'
versionNameSuffix 'jimmy'
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].versionNameSuffix + "/"
logger.error("Path = " + path)
def SEP = "-"
def flavor = variant.productFlavors[0].name
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
}
}
}
dependencies {
}
}
UPDATE
Per the question of using a task, I tried this approach but the problem of setting the directory remains - using a property (archivesBaseName) the last one set is used so all the files are copied to that directory. Here is a sample of that. Since I have upwards of 100 flavors to create I want each sent to it's own directory and config driven. Here is what I tried:
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
setProperty("archivesBaseName", "randy")
}
Jimbo {
applicationId 'com.mycompany.jimmy'
setProperty("archivesBaseName", "jimmy")
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + archivesBaseName + "/"
logger.error("Path = " + path)
def SEP = "-"
def flavor = variant.productFlavors[0].name
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
def copyApkTask = tasks.create(name: "copy" + variant.name + "Apk") {
copy {
def newName = newApkName + ".apk"
logger.error("from = " + newName)
logger.error("into = " + path)
logger.error("old name = " + version + SEP + flavor + ".apk")
logger.error("new name = " + flavor + ".apk")
from newName
into path
rename (version + SEP + flavor + ".apk", flavor + ".apk")
}
}
copyApkTask.mustRunAfter variant.assemble
}
}
In the example above I added a task to additionally copy the APK with different name to a flavor specific directory. All the APKs end up copied to the last specified `archivesBaseName, which is "jimmy". So last one wins. I was hoping it would act like a variable. I would prefer not to have to have 100+ if statements to do this and would prefer to do this in Gradle. I am starting to wonder if I will need to make an external Ant call to make this all work.
Ok, in the end this specific link REALLY helped on the variable assignment which is what I needed:
Android Studio: Gradle Product Flavors: Define custom properties
Basically you can assign variables within the flavor. Here is what I ended up doing, which actually went a bit further than when I started, since now I can use the Flavor as the APK name or specify one (I know, it is messed up, but history can be that way!):
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.mycompany.default"
minSdkVersion 14
targetSdkVersion 23
versionCode 11
versionName "1.0.11"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
productFlavors.whenObjectAdded { flavor ->
// Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
flavor.ext.set('directoryPath', '')
flavor.ext.set('apkName', '')
}
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
directoryPath = 'randy'
apkName = 'RandyBoy' // If you want the APK name be different than the flavor
}
Jimbo {
applicationId 'com.mycompany.jimmy'
directoryPath = 'jimmy'
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].directoryPath + "/"
def SEP = "-"
def apkName = variant.productFlavors[0].apkName
def flavor = variant.productFlavors[0].name
if (apkName != '')
flavor = apkName;
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
}
}
}
dependencies {
}
}
So productFlavors.whenObjectAdded sets the default values for each flavor, which are then overridden by each flavor. In the applicationVariants.all a check is made to see if the apkName has been overridden, if so it uses it, otherwise it uses the flavor name (and the version code is tacked in front of it). The directory is set directly by the flavor.
Big thanks to #lionscribe. He got me thinking this thru more clearly.
The problem is that setProperty is setting the Project property, so it is always being overwritten. A simple solution is to rather use the Varients Extra Property. Something like this.
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
ext.archivesBaseName = "randy" }
Jimbo {
applicationId 'com.mycompany.jimmy'
ext.archivesBaseName=jimmy" }
}
Then you will access it in the task as
def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.ext.archivesBaseName + "/"
I haven't tested it, and it may have a bug, and need some tweaking.
Update
This is not enough, as Gradle will set to the ext property of the flavor object, only if it is defined in the flavor object. Otherwise it will set it in the parent or root object, which is the project. So for this to work, we first have to define the property in the flavor object. This can be done as #Stephen has answered below. Follow his tested method.
There are 3 more options:
1. Use a different variable name for each flavir, by pre-pending the flavor name, like "Jimbo_archivesBaseName". Then access it using property(flavorName + "_archivesBaseName);
2. Use a global HashMap variable, setting a path for each flavor name.
3. Using a function, that returns a path based on flavor name.
Related
I´ve updated my Android Studio today to the 3.3 version which came with Gradle plugin version 4.10.1.
Previously, my build.gradle was renaming my apk´s with this code to the following structure:
app-{buildType[release|debug]}-{flavor[prod|stage]}-{versionName[1.2.4]-{versionCode[43]}.apk
app-release-prod-1.1.4-45.apk.
applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = output.outputFile.name.replace(".apk", "-${variant.versionName}-${variant.versionCode}.apk").replace("-unsigned", "")
}
}
But I got this error after updating.
WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'variant.getPackageApplicationProvider()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration-avoidance.
To determine what is calling variantOutput.getPackageApplication(), use -Pandroid.debug.obsoleteApi=true on the command line to display a stack trace.
Affected Modules: app
The problem is at output.outputFile.name since you can't access output data on this plugin version.
So far I´ve tried this approach without success.
applicationVariants.all { variant ->
variant.flavors*.name.all { flavor ->
outputFileName = "${flavor}-${variant.buildType.name}-${variant.versionName}-${variant.versionCode}.apk".replace("-unsigned", "")
}
}
Any idea?
=======================================================
UPDATE
I took a retake on this matter, I´ve tried the following snippet, but I'm having issues retrieving the flavor of that variant.
android.applicationVariants.all { variant ->
def flavor = variant.flavorName
variant.outputs.all { output ->
def builtType = variant.buildType.name
def versionName = variant.versionName
def versionCode = variant.versionCode
outputFileName = "app-${flavor}-${builtType}-${versionName}-${versionCode}.apk"
}
}
outputs: app--release-1.0.4-88.apk
Thanks
Try this:
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
def builtType = variant.buildType.name
def versionName = variant.versionName
def versionCode = variant.versionCode
def flavor = variant.flavorName
outputFileName = "app-${flavor}-${builtType}-${versionName}-${versionCode}.apk"
}
}
This outputs the following apk name : app-release-myFlavor-0.0.1-1.apk.
Using setProperty method you can rename your .apk name.
You can do this.
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.expertBrains.abc"
minSdkVersion 17
targetSdkVersion 28
versionCode 75
versionName "2.6.15"
multiDexEnabled true
setProperty("archivesBaseName", "(" + versionName + ") "+ new Date().format( 'yyyy-MM-dd HH:mm' ))
}
}
You can do it like this:
defaultConfig {
...
project.ext.set("archivesBaseName", applicationId + "_V" + versionName + "("+versionCode+")_" + new Date().format('dd-MM mm'));
}
As mentioned in the comments, the right way was to use ${variant.getFlavorName()}.apk or variant.baseName.
Can you try below.
applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = outputFileName.replace(".apk", "-${variant.versionName}-${variant.versionCode}.apk").replace("-unsigned", "")
}
}
I hope this could help. I can't say this is the best way but it works.
productFlavour{
uat {
versionName "2.8.74"
buildConfigField("String", "ENVIRONMENT", '"uat"')
setProperty("archivesBaseName", "iotg-uat-v" + versionName)
}
staging {
versionName "2.9.4"
buildConfigField("String", "ENVIRONMENT", '"staging"')
setProperty("archivesBaseName", "iotg-staging-v" + versionName)
}
}
applicationVariants.all { variant ->
variant.outputs.all {
def appName = "AppName"
def buildType = variant.variantData.variantConfiguration.buildType.name
def newName = "${appName}${defaultConfig.versionName}_${buildType}.apk"
outputFileName = newName
}
}
Below code will generate apk file name as
AppName1.2.0_buildType.apk
I have recently upgraded to Gradle 3.0 and now find that the feature to rename the output APK has changed. I think I can get around that, but what I am wondering is whether I can still choose the target directory for the APK. We have existing software that uses a specific APK naming convention and directory structure that I want to maintain. Is there a way to do this?
Here is my current gradle build structure (simplified and renamed to protect the innocent):
android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
defaultConfig {
applicationId "com.mycompany.myapp"
minSdkVersion 15
targetSdkVersion 23
versionCode 23
versionName "23.23.23"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7 }
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.config
}
}
productFlavors.whenObjectAdded { flavor ->
// Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
flavor.ext.set('directoryPath', '')
flavor.ext.set('apkName', '')
}
productFlavors {
MyCompany {
signingConfig signingConfigs.config
directoryPath = mycompany
}
Copper {
applicationId c
signingConfig signingConfigs.config
directoryPath = 'copper'
}
Steel {
applicationId 'com.company2.steel'
signingConfig signingConfigs.config
directoryPath = 'steel'
}
Lead {
applicationId 'com.company3.coal'
signingConfig signingConfigs.config
directoryPath = 'coal'
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyBuilds/" + variant.productFlavors[0].directoryPath + "/"
logger.error("Path = " + path)
def SEP = "-"
def apkName = variant.productFlavors[0].apkName
def flavor = variant.productFlavors[0].name
if (apkName != '')
flavor = apkName;
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
}
}
}
I know that there is now a "Flavor Dimension" which I will just default (I removed that just to make the code a wee bit clearer). The results of running this build should be that 4 different APKs would be generated and placed in their own directory structures, prefixed with the version number (eg "64-Iron.apk").
The naming is working by replacing with "outputfile", but the directory structure does not. Is there a new way to do this under the latest Gradle?
UPDATE (FIXED)
Thanks to the info provided by selected solution, for completeness, here is the final gradle config (again, cleaned to protect the innocent):
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.mycompany.myapp"
minSdkVersion 15
targetSdkVersion 23
versionCode 23
versionName "23.23.23"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7 }
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.config
}
}
productFlavors.whenObjectAdded { flavor ->
// Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
flavor.ext.set('directoryPath', '')
flavor.ext.set('apkName', '')
}
productFlavors {
MyCompany {
signingConfig signingConfigs.config
directoryPath = mycompany
}
Copper {
applicationId c
signingConfig signingConfigs.config
directoryPath = 'copper'
}
Steel {
applicationId 'com.company2.steel'
signingConfig signingConfigs.config
directoryPath = 'steel'
}
Lead {
applicationId 'com.company3.coal'
signingConfig signingConfigs.config
directoryPath = 'coal'
}
}
applicationVariants.all { variant ->
variant.outputs.all {
def apkName = variant.productFlavors[0].apkName
def flavor = variant.productFlavors[0].name
if (apkName != '')
flavor = apkName;
//add here your logic to customize the name of the apk
outputFileName = "${variant.versionCode}-${flavor}.apk"
}
variant.assemble.doLast { assemble ->
//copy the apk in another directory, add here your
//logic to customize the destination folder
copy {
from variant.outputs*.outputFile
into "C:/AndroidBuilds/MyBuilds//${variant.productFlavors[0].directoryPath}"
}
//if you don't want to delete the file after copying it comment the line below
delete variant.outputs*.outputFile
}
}
}
Thanks again MatPag!
UPDATE: Starting from Gradle 3.3.0 assemble property is deprecated. This is the new way to do this:
applicationVariants.all { variant ->
variant.outputs.all {
//add here your logic to customize the name of the apk
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
variant.assembleProvider.configure { assemble ->
assemble.doLast {
//copy the apk in another directory, add here your
//logic to customize the destination folder
copy {
from variant.outputs*.outputFile
//for Windows
into "C:/my_apks/${variant.dirName}"
}
//if you don't want to delete the file after copying it comment the line below
delete variant.outputs*.outputFile
}
}
}
in macOS/Linux you can use something like this for the destination
path:
into "${System.properties['user.home']}/my_apks/${variant.dirName}"
OLD ANSWER (for AGP < 3.3.0):
I've played a bit with Gradle 4.2.1 and AGP 3.0.0, and a possible solution is this one
applicationVariants.all { variant ->
variant.outputs.all {
//add here your logic to customize the name of the apk
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
variant.assemble.doLast { assemble ->
//copy the apk in another directory, add here your
//logic to customize the destination folder
copy {
from variant.outputs*.outputFile
into "C:/my_apks/${variant.dirName}"
}
//if you don't want to delete the file after copying it comment the line below
delete variant.outputs*.outputFile
}
}
I think it's a good starting point to customize the folders based on your needs :)
By default IDE genarate a apk like app-debug.apk or app-release.apk file but I need to generate specific name of the Apk of the App.
For Example:
My application name is iPlanter so i need to generate iPlanter-debug.apk or iPlanter-release.apk instead of app-debug.apk or app-release.apk respectively.
Thanks,
Just add
archivesBaseName = "NAME_YOU_WANT"
in the android{} part of your gradle file.
You'll get "NAME_YOU_WANT-release.apk" as name of the generated file.
Step 1:
Go to root of the main project, under app , right click on app and refactor the app into specific name (example iPlanter) and press ok
Step 2:
Go to Project Setting file which is setting.gradle file
setting.gradle file contains
include ':app'
Now need to replace app by specific name.
For Example
app replace by iPlanter in include ':app'
it looks like below
include ':iPlanter'
then Sync project, after that run your application.
Finally, App generate an apk like iPlanter-debug.apk or iPlanter-release.apk file.
You just have to add following one line of code in app level gradle.
For name only
archivesBaseName = "NAME_YOU_WANT"
defaultConfig {
applicationId "com.PACKAGENAME"
minSdkVersion Integer.parseInt(MIN_SDK_LIBRARY)
targetSdkVersion Integer.parseInt(TARGET_SDK)
versionCode 11
versionName "2.3"
multiDexEnabled true
archivesBaseName = "NAME_YOU_WANT"
}
Name with version
archivesBaseName = "NAME_YOU_WANT" + versionName
defaultConfig {
applicationId "com.PACKAGENAME"
minSdkVersion Integer.parseInt(MIN_SDK_LIBRARY)
targetSdkVersion Integer.parseInt(TARGET_SDK)
versionCode 11
versionName "2.3"
multiDexEnabled true
archivesBaseName = "NAME_YOU_WANT" + versionName
}
You can use this for app name with current date and version
android {
def version = "2.4";
def milestone = "1";
def build = "0";
def name = getDate()+"APP NAME WHAT YOU WANT"+"v"+version
signingConfigs {
config {
….
}
}
compileSdkVersion Integer.parseInt(COMPILE_SDK)
buildToolsVersion BUILD_TOOLS_VERSION
defaultConfig {
applicationId "com.PACKAGENAME"
minSdkVersion Integer.parseInt(MIN_SDK_LIBRARY)
targetSdkVersion Integer.parseInt(TARGET_SDK)
versionCode 11
versionName "2.3"
multiDexEnabled true
}
buildTypes {
debug {
applicationVariants.all { variant ->
variant.outputs.each { output ->
def apk = output.outputFile;
def newName;
newName = apk.name.replace("-" + variant.buildType.name, "")
.replace(project.name, name);
newName = newName.replace("-", "-" + version + "-" + milestone +
"-" + build + "-");
output.outputFile = new File(apk.parentFile, newName);
}
}
}
This will help you. This code will create app name like iPlanter-release.apk or iPlanter-debug.apk
buildTypes {
applicationVariants.all { variant ->
variant.outputs.each { output ->
project.ext { appName = 'iPlanter' }
def newName = output.outputFile.name
newName = newName.replace("app-", "$project.ext.appName-")
output.outputFile = new File(output.outputFile.parent, newName)
}
}
}
Update:
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "iPlanter_${variant.versionName}(${variant.versionCode}).apk"
}
}
It set name like
iPlanter_0.0.1(25).apk
For Android Studio 3, this works for me:
applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = new File("AppName-" + variant.versionName + ".apk");
}
}
Try this code:
defaultConfig{
applicationVariants.all { variant ->
changeAPKName(variant, defaultConfig)
}
}
def changeAPKName(variant, defaultConfig) {
variant.outputs.each { output ->
if (output.zipAlign) {
def file = output.outputFile
output.packageApplication.outputFile = new File(file.parent, "Your APK NAME")
}
def file = output.packageApplication.outputFile
output.packageApplication.outputFile = new File(file.parent, "Your APK NAME")
}
}
For Android Studio 3.1 this works for me:
android {
...............
...............
applicationVariants.all { variant ->
changeAPKName(variant, defaultConfig)
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
.................................
.................................
}
and
def changeAPKName(variant, defaultConfig) {
variant.outputs.all { output ->
outputFileName = new File("xxxxx" + variant.versionName +".apk")
}
}
On my PC, it suffices to rename (through refactor) app to the desired name yourName. After that, include ':app' in setting.grandle file is changed to include ':yourName'. However, in my case I need to close/reopen Android Studio because of sync error. As a result, obtain apk something like yourName-debug.apk and yourName-release.apk.
I'd like to change "app-release.apk" file name to like following when I build an app by using gradle.
[format]
(appname of package name)_V(version code)_(yyMMdd)_(R|T)
[explain]
(appname of package name) : example) com.example.myApp -> myApp
(version code) : build version code 2.2.3 -> 223
(yyMMdd) : build date 2015.11.18 -> 151118
(R|T) : if app is release, "R" but debug is "T".
If I generate an apk file in release, result is : myApp_V223_151118_R.apk.
How to make a file name like this in gradle?
This may be the shortest way:
defaultConfig {
...
applicationId "com.blahblah.example"
versionCode 1
versionName "1.0"
setProperty("archivesBaseName", applicationId + "-v" + versionCode + "(" + versionName + ")")
}
buildType: like so
buildTypes {
debug {
...
versionNameSuffix "-T"
}
release {
...
versionNameSuffix "-R"
}
}
Keep in mind, Android Studio adds versionNameSuffix by build type name by default, so you may not need this.
Upd. In new versions of Android Studio you can it write little shorter(thanks for szx comment):
defaultConfig {
...
archivesBaseName = "$applicationId-v$versionCode($versionName)"
}
Update: Please check Anrimian's answer below which is much simpler and shorter.
Try this:
gradle.properties
applicationName = MyApp
build.gradle
android {
...
defaultConfig {
versionCode 111
...
}
buildTypes {
release {
...
applicationVariants.all { variant ->
renameAPK(variant, defaultConfig, 'R')
}
}
debug {
...
applicationVariants.all { variant ->
renameAPK(variant, defaultConfig, 'T')
}
}
}
}
def renameAPK(variant, defaultConfig, buildType) {
variant.outputs.each { output ->
def formattedDate = new Date().format('yyMMdd')
def file = output.packageApplication.outputFile
def fileName = applicationName + "_V" + defaultConfig.versionCode + "_" + formattedDate + "_" + buildType + ".apk"
output.packageApplication.outputFile = new File(file.parent, fileName)
}
}
Reference:
https://stackoverflow.com/a/30332234/206292
https://stackoverflow.com/a/27104634/206292
2019 / 2020 - How to change APK name For Gradle 3.3, 3.4, 3.5, 4.0 and above
android {
......
applicationVariants.all { variant ->
variant.outputs.all {
def flavor = variant.name
def versionName = variant.versionName
outputFileName = "prefix_${flavor}_${versionName}.apk"
}
}
}
The result would be like this,
prefix_release_1.0.1.apk
I'm trying to set a specific version number in the gradle auto-generated APK filename.
Now gradle generates myapp-release.apk but I want it to look something like myapp-release-1.0.apk.
I have tried renaming options that seems messy. Is there a simple way to do this?
buildTypes {
release {
signingConfig signingConfigs.release
applicationVariants.each { variant ->
def file = variant.outputFile
variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
}
}
I have tried the code above with no luck. Any suggestions?
(using gradle 1.6)
I only have to change the version name in one place. The code is simple too.
The examples below will create apk files named named MyCompany-MyAppName-1.4.8-debug.apk or MyCompany-MyAppName-1.4.8-release.apk depending on the build variant selected.
Note that this solution works on both APK and App Bundles (.aab files).
See Also: How to change the proguard mapping file name in gradle for Android project
#Solution for Recent Gradle Plugin
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.company.app"
minSdkVersion 13
targetSdkVersion 21
versionCode 14 // increment with every release
versionName '1.4.8' // change with every release
setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName")
}
}
The above solution has been tested with the following Android Gradle Plugin Versions:
3.6.4 (August 2020)
3.5.2 (November 2019)
3.3.0 (January 2019)
3.1.0 (March 2018)
3.0.1 (November 2017)
3.0.0 (October 2017)
2.3.2 (May 2017)
2.3.1 (April 2017)
2.3.0 (February 2017)
2.2.3 (December 2016)
2.2.2
2.2.0 (September 2016)
2.1.3 (August 2016)
2.1.2
2.0.0 (April 2016)
1.5.0 (2015/11/12)
1.4.0-beta6 (2015/10/05)
1.3.1 (2015/08/11)
I'll update this post as new versions come out.
#Solution Tested Only on versions 1.1.3-1.3.0
The following solution has been tested with the following Android Gradle Plugin Versions:
1.3.0 (2015/07/30) - Not Working, bug scheduled to be fixed in 1.3.1
1.2.3 (2015/07/21)
1.2.2 (2015/04/28)
1.2.1 (2015/04/27)
1.2.0 (2015/04/26)
1.2.0-beta1 (2015/03/25)
1.1.3 (2015/03/06)
app gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.company.app"
minSdkVersion 13
targetSdkVersion 21
versionCode 14 // increment with every release
versionName '1.4.8' // change with every release
archivesBaseName = "MyCompany-MyAppName-$versionName"
}
}
This solved my problem: using applicationVariants.all instead of applicationVariants.each
buildTypes {
release {
signingConfig signingConfigs.release
applicationVariants.all { variant ->
def file = variant.outputFile
variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
}
}
}
Update:
So it seems this does not work with 0.14+ versions of android studio gradle plugin.
This does the trick (Reference from this question
) :
android {
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
}
}
}
(EDITED to work with Android Studio 3.0 and Gradle 4)
I was looking for a more complex apk filename renaming option and I wrote this one in the hope it is helpfull for anyone else. It renames the apk with the following data:
flavor
build type
version
date
It took me a bit of research in gradle classes and a bit of copy/paste from other answers. I am using gradle 3.1.3.
In the build.gradle:
android {
...
buildTypes {
release {
minifyEnabled true
...
}
debug {
minifyEnabled false
}
}
productFlavors {
prod {
applicationId "com.feraguiba.myproject"
versionCode 3
versionName "1.2.0"
}
dev {
applicationId "com.feraguiba.myproject.dev"
versionCode 15
versionName "1.3.6"
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
def project = "myProject"
def SEP = "_"
def flavor = variant.productFlavors[0].name
def buildType = variant.variantData.variantConfiguration.buildType.name
def version = variant.versionName
def date = new Date();
def formattedDate = date.format('ddMMyy_HHmm')
def newApkName = project + SEP + flavor + SEP + buildType + SEP + version + SEP + formattedDate + ".apk"
outputFileName = new File(newApkName)
}
}
}
If you compile today (13-10-2016) at 10:47, you get the following file names depending on the flavor and build type you have choosen:
dev debug: myProject_dev_debug_1.3.6_131016_1047.apk
dev release: myProject_dev_release_1.3.6_131016_1047.apk
prod debug: myProject_prod_debug_1.2.0_131016_1047.apk
prod release: myProject_prod_release_1.2.0_131016_1047.apk
Note: the unaligned version apk name is still the default one.
To sum up, for those don't know how to import package in build.gradle(like me), use the following buildTypes,
buildTypes {
release {
signingConfig signingConfigs.release
applicationVariants.all { variant ->
def file = variant.outputFile
def manifestParser = new com.android.builder.core.DefaultManifestParser()
variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile) + ".apk"))
}
}
}
===== EDIT =====
If you set your versionCode and versionName in your build.gradle file like this:
defaultConfig {
minSdkVersion 15
targetSdkVersion 19
versionCode 1
versionName "1.0.0"
}
You should set it like this:
buildTypes {
release {
signingConfig signingConfigs.releaseConfig
applicationVariants.all { variant ->
def file = variant.outputFile
variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
}
}
}
====== EDIT with Android Studio 1.0 ======
If you are using Android Studio 1.0, you will get an error like this:
Error:(78, 0) Could not find property 'outputFile' on com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated#67e7625f.
You should change the build.Types part to this:
buildTypes {
release {
signingConfig signingConfigs.releaseConfig
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
}
}
}
}
If you don't specify versionName in defaultConfig block then defaultConfig.versionName will result in null
to get versionName from manifest you can write following code in build.gradle:
import com.android.builder.DefaultManifestParser
def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Gradle 6+
I'm now using the following in Android Studio 4.0 and Gradle 6.4:
android {
defaultConfig {
applicationId "com.mycompany.myapplication"
minSdkVersion 21
targetSdkVersion 29
versionCode 15
versionName "2.1.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "ApplicationName-${variant.name}-${variant.versionName}.apk"
}
}
}
}
}
Gradle 4
Syntax has changed a bit in Gradle 4 (Android Studio 3+) (from output.outputFile to outputFileName, idea from this answer is now:
android {
applicationVariants.all { variant ->
variant.outputs.each { output ->
def newName = outputFileName
newName.replace(".apk", "-${variant.versionName}.apk")
outputFileName = new File(newName)
}
}
}
In my case, I just wanted to find a way to automate the generation of different apk name for release and debug variants. I managed to do this easily by putting this snippet as a child of android:
applicationVariants.all { variant ->
variant.outputs.each { output ->
def appName = "My_nice_name_"
def buildType = variant.variantData.variantConfiguration.buildType.name
def newName
if (buildType == 'debug'){
newName = "${appName}${defaultConfig.versionName}_dbg.apk"
} else {
newName = "${appName}${defaultConfig.versionName}_prd.apk"
}
output.outputFile = new File(output.outputFile.parent, newName)
}
}
For the new Android gradle plugin 3.0.0 you can do something like that:
applicationVariants.all { variant ->
variant.outputs.all {
def appName = "My_nice_name_"
def buildType = variant.variantData.variantConfiguration.buildType.name
def newName
if (buildType == 'debug'){
newName = "${appName}${defaultConfig.versionName}_dbg.apk"
} else {
newName = "${appName}${defaultConfig.versionName}_prd.apk"
}
outputFileName = newName
}
}
This produce something like : My_nice_name_3.2.31_dbg.apk
Another alternative is to use the following:
String APK_NAME = "appname"
int VERSION_CODE = 1
String VERSION_NAME = "1.0.0"
project.archivesBaseName = APK_NAME + "-" + VERSION_NAME;
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "com.myapp"
minSdkVersion 15
targetSdkVersion 21
versionCode VERSION_CODE
versionName VERSION_NAME
}
.... // Rest of your config
}
This will set "appname-1.0.0" to all your apk outputs.
The right way to rename apk, as per #Jon answer
defaultConfig {
applicationId "com.irisvision.patientapp"
minSdkVersion 24
targetSdkVersion 22
versionCode 2 // increment with every release
versionName "0.2" // change with every release
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//add this line
archivesBaseName = "AppName-${versionName}-${new Date().format('yyMMdd')}"
}
Or another way you can achieve same results with
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
def formattedDate = new Date().format('yyMMdd')
outputFileName = "${outputFileName.replace(".apk","")}-v${defaultConfig.versionCode}-${formattedDate}.apk"
}
}
}
There are many answers that are correct either in full or after some modifications. But I am going to add mine anyway since I was having the problem with all of them because I was using scripts to generate VersionName and VersionCode dynamically by hooking into the preBuild task.
If you are using some similar approach this is the the code that will work:
project.android.applicationVariants.all { variant ->
variant.preBuild.doLast {
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
output.outputFile.name.replace(".apk", "-${variant.versionName}#${variant.versionCode}.apk"))
}
}
}
To explain: Since I am overriding version code and name in the first action of preBuild I have to add the file renaming to the end of this task. So what gradle will do in this case is:
Inject version code/name-> do preBuild actions -> replace name for apk
applicationVariants.all { variant ->
variant.outputs.all { output ->
output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
}
}
In my case I solve this error this way
adding a SUFFIX to the Debug version, in this case I adding the "-DEBUG" text to my Debug deploy
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
defaultConfig {
debuggable true
versionNameSuffix "-DEBUG"
}
}
}
For latest gradle versions you can use following snippet:
Set your application manifest location first
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
{
}
And later on in build.gradle
import com.android.builder.core.DefaultManifestParser
def getVersionName(manifestFile) {
def manifestParser = new DefaultManifestParser();
return manifestParser.getVersionName(manifestFile);
}
def manifestFile = file(android.sourceSets.main.manifest.srcFile);
def version = getVersionName(manifestFile)
buildTypes {
release {
signingConfig signingConfigs.release
applicationVariants.each { variant ->
def file = variant.outputFile
variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + versionName + ".apk"))
}
}
Adjust if you have different manifests per build type. but since I have the single one - works perfectly for me.
As of Android Studio 1.1.0, I found this combination worked in the android body of the build.gradle file. This is if you can't figure out how to import the manifest xml file data. I wish it was more supported by Android Studio, but just play around with the values until you get the desired apk name output:
defaultConfig {
applicationId "com.package.name"
minSdkVersion 14
targetSdkVersion 21
versionCode 6
versionName "2"
}
signingConfigs {
release {
keyAlias = "your key name"
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "appName_" + versionName + ".apk"))
}
}
}
}
As I answered here If you want to append the version name and version code to the output file do it like:
applicationVariants.all { variant ->
variant.outputs.all {
def versionName = variant.versionName
def versionCode = variant.versionCode
def variantName = variant.name
outputFileName = "${rootProject.name}" + '_' + variantName + '_' + versionName + '_' + versionCode + '.apk'
}
}
You can also add formatted build time to apk name as below:
setProperty("archivesBaseName", "data-$versionName " + (new Date().format("HH-mm-ss")))
Here is how you can do it in the Kotlin DSL:
applicationVariants.all {
outputs.all {
this as com.android.build.gradle.internal.api.ApkVariantOutputImpl
val apkName = outputFileName.replace(".apk", "-" + defaultConfig.versionName + ".apk")
outputFileName = apkName
}
}