186

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)

Brian S
  • 3,096
  • 37
  • 55
Coy
  • 3,703
  • 3
  • 14
  • 13

17 Answers17

246

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"
    }
}
kabumere
  • 353
  • 2
  • 8
Jon
  • 9,156
  • 9
  • 56
  • 73
  • 12
    I think this is the right approach instead of writing another task to rename files. – Nandish A May 28 '15 at 12:29
  • 5
    just change to archivesBaseName = "MyCompany-MyAppName-$versionName" if you have OCD and do not want AS warn you about the + – ligi Jul 02 '15 at 12:53
  • this is scheduled to be deprecated in gradle 2+ see http://stackoverflow.com/a/20660274/774398 – Patrick Aug 04 '15 at 14:53
  • @for3st I'll soon update the answer with a gradle 2+ version which is `setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName")` – Jon Aug 25 '15 at 13:56
  • can version name be set when build starts..? My goal would be to have auto generated versionName that will look like "1.4.8 (20150825_115958)".. Version 1.4.8 can be still set in gradle build file but timestamp would be assigned automatically. Generated apk would have same timestamp as suffix in file name like "MyApp_v1.4.8_20150825_115958" .. – Ewoks Sep 23 '15 at 08:33
  • @Ewoks `def date = new Date().format('yyyyMMddHHmmss')` and `setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName-$date")` seem close to what you're asking for and while it seems to generate apk's with the date in the file name, android studio can't automatically install them, throwing *Local path doesn't exist* in my tests. I wonder why you want this in the first place as gradle builds, when used with git are repeatable. Having timestamps on a binary doesn't really tell me anything about the code used to generate it. – Jon Sep 23 '15 at 22:55
  • it tells my customer and it is easier for me to communicate with them when there is timestamp.. I found other way in the mean time but as you said Android Studio for some reason doesn't find that file – Ewoks Sep 24 '15 at 07:56
  • I combined this answer with an auto-increment of version code SO answer (stackoverflow.com/a/25166200/1876622) so that I don't have to manually change each build number during development. – HeyZiko Oct 19 '15 at 19:03
  • Putting ```setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName")``` in your ```defaultConfig```works nicely with gradle:1.5.0 plugin. – Kerem Feb 12 '16 at 11:19
  • setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName") works perfectlly with gradle:2.0.0, Many thanks – Simon K. Gerges Apr 13 '16 at 07:25
  • 4
    Great find, but doesn't work well with flavors with different version codes. They all end up with same version code. – weston May 06 '17 at 15:08
  • Is there not any variable name for MyAppName? That seems odd. I mean the hardcoded string literals "MyCompany-MyAppName-$versionName" – deLock Apr 27 '18 at 06:30
  • Doesn't work with Bundles, any update to make it work with bundles? – strangetimes Jun 16 '18 at 13:58
  • @deLock in case you or someone else is wondering - you can set the variable `applicationName` in the **gradle.properties** file and use it in the build.gradle like so: `setProperty("archivesBaseName", "$applicationName-$versionName")`. Or you can use the `$applicationId` variable – Netherdan Aug 07 '18 at 18:11
  • 4
    Is there any way to add `variant.buildType.name` to the name? I know this isn't really default config related, but I'm trying to figure out how to remove the obsolete `variantOutput.getAssemble()` warning – Allan W Mar 05 '19 at 05:51
  • 4
    Is it possible to remove from apk name last '-debug' / '-release'? – ilyamuromets May 27 '19 at 15:53
  • 1
    Excellent approach. Makes it easy to modify file output, especially when producing Split APKs. – Kellin Strook Apr 12 '20 at 14:03
175

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"))
        }
    }
}
Community
  • 1
  • 1
Coy
  • 3,703
  • 3
  • 14
  • 13
  • 3
    Do you know how to get it working if I have a `versionName` defined in `AndroidManifest.xml` instead of gradle config? It gives me `myapp-release-null.apk` now. – Iwo Banas Oct 02 '13 at 09:06
  • Anybody know how to do this if the version name is defined in the gradle file, but in the flavors rather than the defaultConfig? – nasch Aug 11 '14 at 14:11
  • 1
    This answer doesn't work with 0.14+ versions of the gradle plugin. Any updates to work with those? – Argyle Nov 21 '14 at 19:04
  • @Argyle you'd need to work with all the possible output files at once utilizing something like: `variant.outputs.each { output -> output.setOutputFile(new File (file.parent, some_new_filename) }` – withoutclass Dec 01 '14 at 20:12
  • 1
    @withoutclass I asked this as it's own question and got it answered here: http://stackoverflow.com/questions/27068505/how-do-i-add-a-version-number-to-my-apk-files-using-0-14-versions-of-the-androi?lq=1 – Argyle Dec 01 '14 at 20:43
  • This piece of code works, but it seem to trigger a bug in Android Studio that hangs the IDE when editing (on Linux). Another script that causes this: https://code.google.com/p/android/issues/detail?id=187493 – Amir Uval Nov 24 '15 at 16:54
  • 2
    For people updating to Gradle 4: change `each` to `all` and `output.outputFile` to `outputFileName`. If somebody confims this works it can be edited into the answer :) – PHPirate Oct 29 '17 at 16:19
  • 6
    @PHPirate: almost works: `Error:(34, 0) Cannot set the value of read-only property 'name'` – Mooing Duck Dec 10 '17 at 02:11
  • @MooingDuck Yeah sorry I was a bit vague, does the following work for you? Same as in answer but `output -> def newName = outputFileName; newName.replace(".apk", "-${variant.versionName}.apk"); outputFileName = new File(newName)` – PHPirate Dec 10 '17 at 15:56
  • Or a bit simpified, `output -> outputFileName = "${variant.name}-${variant.versionName}.apk"`. I added a [new answer](https://stackoverflow.com/a/47740978/4126843) in which it looks much clearer. – PHPirate Dec 10 '17 at 16:37
  • Looks like this broke again in gradle 6 – spartygw Jun 10 '20 at 00:43
51

(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.

Fer
  • 1,956
  • 2
  • 28
  • 35
  • is it possible to use the same approach in Xamarin Studio? – Alessandro Caliaro Dec 01 '16 at 11:12
  • It would be great if it was possible, but I am starting right now a Xamarin course and I still haven't enough practice with it to know if it is possible or not. I will ask this question and come here again. – Fer Dec 01 '16 at 11:31
  • Comment from the teacher of the course: "there is an option where you can use commands in order to change the name of the generated files". Therefore, the approach to use from Xamarin must be different to the one I wrote for Android Studio, sorry. – Fer Dec 02 '16 at 09:38
  • 3
    To resolve the error **Cannot set the value of read-only property 'outputFile'** - as mentioned in an earlier comment for having to *"change `each` to `all` and `output.outputFile` to `outputFileName` "* - this post provides some details on that: https://stackoverflow.com/a/44265374/2162226 – Gene Bo Dec 25 '17 at 00:41
  • I have edited the answer with this suggestion. Thanks @gnB – Fer Jun 18 '18 at 14:18
  • variant.variantData.variantConfiguration.buildType.name should be replaced with variant.buildType.name – Kirill Kostrov Feb 15 '21 at 16:43
19

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"))
                }
            }
        }
    }
Wesley
  • 4,084
  • 6
  • 37
  • 60
  • This works great. However, since I increment my manifest version in the gradle build, it will create an APK with the older (pre-increment) value. Any way to make sure this takes affect after the gradle script increment the version number? – Guy Aug 30 '14 at 18:06
  • 1
    @Guy Sorry took so long. I edited the answer, see if it can solve your problem. – Wesley Sep 09 '14 at 03:30
17

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)
Arkadiusz Konior
  • 1,139
  • 13
  • 12
  • 7
    I believe that with later versions of gradle, it is now com.android.builder.core.DefaultManifestParser – Ryan S Jun 16 '14 at 06:33
9

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)
        }
    }
}
PHPirate
  • 7,023
  • 7
  • 48
  • 84
8

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

yshahak
  • 4,996
  • 1
  • 31
  • 37
7

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.

Marco RS
  • 8,145
  • 3
  • 37
  • 45
6

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"
        }
    }
}
Jon
  • 9,156
  • 9
  • 56
  • 73
Qamar
  • 4,959
  • 1
  • 30
  • 49
3

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

Xiao
  • 1,552
  • 2
  • 22
  • 20
Igor Čordaš
  • 5,785
  • 4
  • 42
  • 54
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
timeon
  • 2,194
  • 4
  • 18
  • 19
  • While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Rosário Pereira Fernandes Feb 18 '18 at 00:05
1

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"
            }
        }
    }
exequielc
  • 681
  • 1
  • 11
  • 32
  • This doesn't change the APK filename. – Tom Aug 24 '17 at 23:03
  • 1
    This is a nice tip, actually. Not in the right question, but good one. Where can I read more about it? Is it possible to use `versionNameSuffix` based on the GIT branch? For example, if it's not on "master", always have a suffix, even if it's a release version – android developer Aug 15 '19 at 08:28
0

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.

Alfishe
  • 3,430
  • 1
  • 25
  • 19
0

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"))
                }
            }
        }
    }
A13X
  • 409
  • 1
  • 6
  • 27
0

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'
        }
    }
Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138
0

You can also add formatted build time to apk name as below:

setProperty("archivesBaseName", "data-$versionName " + (new Date().format("HH-mm-ss")))
Hadi
  • 544
  • 1
  • 8
  • 28
0

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
    }
}
Veniamin
  • 774
  • 5
  • 12