How to change the proguard mapping file name in gradle for Android project
Asked Answered
V

13

29

I have android project based on gradle and I want to change mapping.txt file name after it's generated for my build. How can it be done?

upd

How it can be done in build.gradle? Since I have access there to my flavors and other stiff, I would like to create mapping file name based on flavor/build variant version.

Victorvictoria answered 9/3, 2015 at 17:48 Comment(1)
Does my proposition is helpful for you?Rancho
N
8

As of today (May 2020) former solution, which uses variant.mappingFile is not working anymore in new Android Gradle plugin (Android Studio) 3.6 and higher.

Instead variant.mappingFile returns null and following is displayed in the logs:

WARNING: API 'variant.getMappingFile()' is obsolete and has been replaced with 'variant.getMappingFileProvider()'.

I am sharing my working solution, which uses new api:


    applicationVariants.all { variant ->
        variant.assembleProvider.get().doLast {
            def mappingFiles = variant.getMappingFileProvider().get().files

            for (file in mappingFiles) {
                if (file != null && file.exists()) {
                    def nameMatchingApkFile = "$archivesBaseName-$variant.baseName-$file.name"
                    def newMappingFile = new File(file.parent, nameMatchingApkFile)

                    newMappingFile.delete() //clean-up if exists already
                    file.renameTo(newMappingFile)
                }
            }
        }
    }

Note, that variant.getBuildType().isMinifyEnabled() is not used since we are using DexGuard.

The code above makes mapping file's name match apk's file name.

Just in case, if you need to change apk name - following could be used:

android {
    defaultConfig {
        //resulting apk will looks like: "archive base name" + -<flavour>-<buildType>.apk
        archivesBaseName = "$applicationId-$versionName"
    }
}

Nix answered 22/5, 2020 at 11:33 Comment(0)
P
49

Simpler solution.

applicationVariants.all { variant ->
        if (variant.getBuildType().isMinifyEnabled()) {
            variant.assemble.doLast {
                copy {
                    from variant.mappingFile
                    into "${rootDir}/proguardTools"
                    rename { String fileName ->
                        "mapping-${variant.name}.txt"
                    }
                }
            }
        }
    }
Parenthesis answered 29/6, 2015 at 13:9 Comment(6)
Excellent, thanks. You can alternatively use rename { String fileName -> "mapping-${variant.getFlavorName()}.txt" } if you have multiple product flavors and don't want to include the buildType.Golly
Great solution! But why the redundant loop on variant.outputs? There is no reference to output inside the loop.Copestone
In case you just need to rename the existing mapping file without copying it to a new location, use this code fragment: def mappingFile = variant.mappingFile mappingFile.renameTo(mappingFile.parent + "/newName.txt")Backandforth
script is also in this blog post: medium.com/@xabaras/…Batten
Do you have a working script for case when I'm generating App bundle instead of APK? Because then there is no assemble task but bundle task is ran instead. And there is no bundle property to hook doLast {} on.Deucalion
@Deucalion Unfortunately no, and since then I stopped working with AndroidParenthesis
N
8

As of today (May 2020) former solution, which uses variant.mappingFile is not working anymore in new Android Gradle plugin (Android Studio) 3.6 and higher.

Instead variant.mappingFile returns null and following is displayed in the logs:

WARNING: API 'variant.getMappingFile()' is obsolete and has been replaced with 'variant.getMappingFileProvider()'.

I am sharing my working solution, which uses new api:


    applicationVariants.all { variant ->
        variant.assembleProvider.get().doLast {
            def mappingFiles = variant.getMappingFileProvider().get().files

            for (file in mappingFiles) {
                if (file != null && file.exists()) {
                    def nameMatchingApkFile = "$archivesBaseName-$variant.baseName-$file.name"
                    def newMappingFile = new File(file.parent, nameMatchingApkFile)

                    newMappingFile.delete() //clean-up if exists already
                    file.renameTo(newMappingFile)
                }
            }
        }
    }

Note, that variant.getBuildType().isMinifyEnabled() is not used since we are using DexGuard.

The code above makes mapping file's name match apk's file name.

Just in case, if you need to change apk name - following could be used:

android {
    defaultConfig {
        //resulting apk will looks like: "archive base name" + -<flavour>-<buildType>.apk
        archivesBaseName = "$applicationId-$versionName"
    }
}

Nix answered 22/5, 2020 at 11:33 Comment(0)
R
7

Use this command in your proguard-rules.pro file:

-printmapping path/to/your/file/file_name.txt

the file will be written in part {root}/path/to/your/file with file_name.txt name.

If you want to have different setting for different flavors you can define many proguard-rules for them

I found one more idea but I am not sure that it is right way.

You can define your path in flavors:

productFlavors {
    test1 {
        applicationId "com.android.application.test"
        project.ext."${name}Path" = 'path/one/mapp.txt'
    }
    test2 {
        project.ext."${name}Path" = 'path/two/mapp.txt'
    }
}

And as next you can define new task before $asseble{variant.name.capitalize()} task as is shown below:

android.applicationVariants.all { variant ->
    def envFlavor = variant.productFlavors.get(0).name

    def modifyProguardPath = tasks.create(name: "modifyProguardFor${variant.name.capitalize()}", type: Exec) {
        def pathToMap = project."${envFlavor}Test1"
        doFirst {
            println "==== Edit start: $pathToMap ===="
        }
        doLast {
            println "==== Edit end: $pathToMap ===="
        }
        executable "${rootDir}/utils/test.bash"
        args pathToMap
    }

    project.tasks["assemble${variant.name.capitalize()}"].dependsOn(modifyProguardPath);
}

and in script ${root}/utils/test.bash - you can modify proguard-rules.pro.

But I think that exist better solution.

Rancho answered 9/3, 2015 at 17:56 Comment(5)
Ok, I will try, but maybe you know the way how to do this in build.gradle? Since I have access there to my flavors and other stiff I would like to create mapping file name based on flavor/build variant version.Victorvictoria
I never do this programmatically but I can check some idea. If I find working solution I will inform youRancho
Konrad, thank you, this instruction '-printmapping build/outputs/mapping/mymapping.txt' works, but it's not the case for me to create different proguard rules for each build variant since I have a lot of instructions there and I would avoid duplicating this in different files. I still looking for some way to do this from build.gradle script.Victorvictoria
@Victorvictoria Hi I found some working solution but it is not the best way. If my answer was helpful for you please give me upvoteRancho
Looks good, thank you, but I finally found right solution for me, it looks a bit different.Victorvictoria
V
5

Many thanx to Sergii Pechenizkyi who helped me to found this good solution.

To implement copying of proguard mapping files for each flavor we can create "root" task copyProguardMappingTask and number of dynamic tasks for each flavor

def copyProguardMappingTask = project.tasks.create("copyProguardMapping")
applicationVariants.all { variant ->
    variant.outputs.each { output ->
        ...
        if (variant.getBuildType().isMinifyEnabled()) {
            def copyProguardMappingVariantTask = project.tasks.create("copyProguardMapping${variant.name.capitalize()}", Copy)

            def fromPath = variant.mappingFile;
            def intoPath = output.outputFile.parent;

            copyProguardMappingVariantTask.from(fromPath)
            copyProguardMappingVariantTask.into(intoPath)
            copyProguardMappingVariantTask.rename('mapping.txt', "mapping-${variant.name}.txt")

            copyProguardMappingVariantTask.mustRunAfter variant.assemble
            copyProguardMappingTask.dependsOn copyProguardMappingVariantTask
        }
    }
}

afterwards we should run this task after assembling our project. I use jenkins and my tasks option looks like

gradle clean assembleProjectName copyProguardMapping

It works like a charm.

Victorvictoria answered 13/3, 2015 at 10:53 Comment(0)
W
4

Since the last update variant.mappingFile is not longer available. (I use ProGuard version 4.7, AndroidStudio 2.0)

This is (part of) my build.gradle file:

import java.util.regex.Matcher
import java.util.regex.Pattern

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else
    {
        println "NO MATCH FOUND"
        return "";
    }
}

buildTypes {
    release {
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        minifyEnabled true

        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                output.outputFile = new File(output.outputFile.parent, "${variant.name}_v${variant.versionName}.apk")
            }
            def mappingFile = "${rootDir}\\app\\build\\outputs\\mapping\\${getCurrentFlavor()}\\release\\mapping.txt"
            println("mappingFile:  ${mappingFile}")
            if (variant.getBuildType().isMinifyEnabled()) {
                variant.assemble.doLast {
                    copy {
                        from "${mappingFile}"
                        into "${rootDir}"
                        rename { String fileName ->
                            "mapping-${variant.name}.txt"
                        }
                    }
                }
            }
        }

    }

    debug {
        minifyEnabled false
        useProguard false

        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                output.outputFile = new File(output.outputFile.parent, "${variant.name}_v${variant.versionName}.apk")
            }
        }
    }

}
Whity answered 17/4, 2016 at 14:55 Comment(3)
Thanks..! Its worked, but did not understand the problemZebec
actually I was getting null pointer exception at line "from variant.mappingFile" after updating gradle 1.5.0 to 2.1.0, it would be great if you can explain itZebec
Yeah I'm getting that tooFayalite
P
4

This is a variation of igorpst's answer but renames mapping.txt to match the apk's name exactly including the app version name. I've combined this with code to name the APK with a version number as described in this answer. I had to snoop through the gradle source code to find $variant.baseName

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"
    }
    applicationVariants.all { variant ->
        if (variant.getBuildType().isMinifyEnabled()) {
            variant.assemble.doLast {
                (new File(variant.mappingFile.parent, "$archivesBaseName-$variant.baseName-mapping.txt")).delete();
                variant.mappingFile.renameTo(variant.mappingFile.parent +
                        "/$archivesBaseName-$variant.baseName-mapping.txt")
            }
        }
    }
}
Placid answered 31/3, 2017 at 14:10 Comment(0)
M
4

variant.assemble is now deprecated, suggested solution incorporating previous modifications:

archivesBaseName = "MyCompany-MyAppName-$versionName"
...
applicationVariants.all { variant ->
    variant.assembleProvider.get().doLast {
        if (variant.mappingFile != null && variant.mappingFile.exists()) {
            def mappingFilename = "$archivesBaseName-$variant.baseName-mapping.txt"
        (new File(variant.mappingFile.parent, mappingFilename)).delete()
        variant.mappingFile.renameTo(variant.mappingFile.parent +
                "/" + mappingFilename)
        }
    }
}

If using app bundle (aab) instead of apk, add this to after the android section:

afterEvaluate {
    bundleRelease.doLast {
        android.applicationVariants.all { variant ->
            if (variant.buildType.name == 'release') {
                tasks.create(name: "renameMappingFile") {
                    if (variant.mappingFile != null && variant.mappingFile.exists()) {
                        variant.mappingFile.renameTo(variant.mappingFile.parent + "/$variant.baseName-$versionName-${new Date().format('yyyy-MM-dd_HHmm')}-mapping.txt")
                    }
                }
            }
        }
    }
}

Swap bundleRelease for assembleRelease for apks in the last example too.

Update: However that last doesn't work if you try and build a normal debug directly to your phone then. Error:

Could not get unknown property 'bundleRelease' for project ':app' of type org.gradle.api.Project.

Mcneese answered 30/1, 2019 at 14:4 Comment(0)
L
2

All these answers used copy to rename the file. I didn't want to move the file however, I just wanted to change it's name, keeping in mind the build type and flavor.

I based myself on the code from the other posters here and changed it up a bit. Since Minify can be false, while still using proguard, I just check if the file is present.

Following code accomplishes just that.

android {
    applicationVariants.all { variant ->
        variant.assemble.doLast {
            def mappingFolderUrl = "${project.buildDir.path}/outputs/mapping/"

            if (variant.buildType.name) {
                mappingFolderUrl += variant.buildType.name + "/"
            }

            if (variant.flavorName) {
                mappingFolderUrl += variant.flavorName + "/"
            }

            def mappingFileUrl = mappingFolderUrl + "mapping.txt"
            logger.lifecycle("mappingFile path: ${mappingFileUrl}")

            File mappingFile = file(mappingFileUrl)
            if (mappingFile.exists()) {
                def newFileName = mappingFolderUrl + "mapping-${variant.name}.txt"
                mappingFile.renameTo(newFileName)
            }
        }
    }
}

NOTE

You could probably use this code to move the file as well.

the .renameTo() method expects a full path, If you change the path, I would suppose you effectively move the File to another place.

Lenardlenci answered 21/2, 2017 at 17:40 Comment(0)
P
2

For Android Studio Gradle Plugin Version 4.1.0 and newer (since about May 2020)

This version fixes the following warning:

WARNING: API 'variant.getMappingFile()' is obsolete and has been replaced with 'variant.getMappingFileProvider()'.

applicationVariants.all { variant ->
    variant.assembleProvider.get().doLast {
        def mappingFileProvider = variant.getMappingFileProvider().get()
        if (mappingFileProvider != null) {
            try {
                def mappingFiles = mappingFileProvider.getFiles()

                for (mappingFile in mappingFiles) {
                    if (mappingFile != null && mappingFile.exists()) {
                        def newMappingFileName = "$archivesBaseName-$variant.baseName-$mappingFile.name"
                        project.logger.lifecycle("Renaming '${mappingFile.name}' to '${newMappingFileName}'")
                        def newMappingFile = new File(mappingFile.parent, newMappingFileName)

                        newMappingFile.delete()
                        mappingFile.renameTo(newMappingFile)
                    }
                }
            } catch (Exception ignored) {
                project.logger.lifecycle("No mapping files found to rename")
            }
        }
    }
}

For Android Studio Gradle Plugin Version 3.3.0 (January 2019) through about May 2020 This overcomes previous issues where Android 3.0/Android Gradle Plugin 3.0 deprecated BuildType.isMinifyEnabled() and the gradle plugin deprecated variant.getAssemble().

applicationVariants.all { variant ->
    variant.assembleProvider.get().doLast {
        if (variant.mappingFile != null && variant.mappingFile.exists()) {
            def mappingFilename = "$archivesBaseName-$variant.baseName-mapping.txt"
            (new File(variant.mappingFile.parent, mappingFilename)).delete()
            variant.mappingFile.renameTo(variant.mappingFile.parent +
                    "/" + mappingFilename)
        }
    }
}
Placid answered 13/11, 2017 at 17:52 Comment(0)
C
2

A complete solution that worked for me

applicationVariants.all { variant ->
        def variantType = variant.buildType.name
        if (variantType == "release") {
            variant.assemble.doLast {
                def mappingFile = variant.mappingFile
                mappingFile.renameTo(mappingFile.parent + "/mapping-${variant.name}.txt")       
            }
        }
    }
Cuesta answered 21/4, 2020 at 22:51 Comment(0)
G
0

Pinhassi's solution above works great and it is conforms to the latest Gradle changes. There are a couple of things though that I had to change:

  1. The module name is hardcoded ("app"), which is not ideal since in a lot of cases (including mine) that will not be true. It is better to dynamically detect the module name.
  2. The mapping file also only conforms to the Windows file system by having backward escaped slashes ("\"). If you are on a *NIX system like Linux or Mac, you need to replace those with forward non escaped slashes ("/")
  3. Changed a bit the renaming of the .apk file to include the project name and added a date/time stamp at the end.

Here is the finished code:

import java.util.regex.Matcher
import java.util.regex.Pattern

buildTypes {
        release {
        debuggable false
        minifyEnabled true
        proguardFiles 'proguard.cfg'

        // Rename the apk file and copy the ProGuard mapping file to the root of the project
        applicationVariants.all { variant ->
            if (variant.getBuildType().name.equals("release")) {
                def formattedDate = new Date().format('yyyyMMddHHmmss')
                def projectName = ""
                variant.outputs.each { output ->
                    def fullName = output.outputFile.name
                    projectName = fullName.substring(0, fullName.indexOf('-'))
                    // ${variant.name} has the value of "paidRelease"
                    output.outputFile = new File((String) output.outputFile.parent, (String) output.outputFile.name.replace(".apk", "-v${variant.versionName}-${formattedDate}.apk"))
                }
                def mappingFile = "${rootDir}/${projectName}/build/outputs/mapping/${getCurrentFlavor()}/release/mapping.txt"
                println("mappingFile:  ${mappingFile}")
                if (variant.getBuildType().isMinifyEnabled()) {
                    variant.assemble.doLast {
                        copy {
                            from "${mappingFile}"
                            into "${rootDir}"
                            rename { String fileName ->
                                "mapping-${variant.name}.txt"
                            }
                        }
                    }
                }
            }
        }
    }

        debug {
            debuggable true
        }
    }

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else {
        println "NO MATCH FOUND"
        return "";
    }
}
Griskin answered 4/7, 2016 at 2:30 Comment(0)
B
0
applicationVariants.all { variant ->
    variant.outputs.each { output ->
        if (variant.getBuildType().isMinifyEnabled()) {
            variant.assemble.doLast{
                copy {
                    from variant.mappingFile
                    into "${rootDir}/mapping"
                    rename { String fileName ->
                        "mapping-${variant.name}-${new Date().format('yyyy_MM_dd')}.txt"
                    }
                }
            }
        }
    }
}
Bertilla answered 10/11, 2016 at 12:23 Comment(0)
L
0

Here is solution that helps me:

  • compileSdkVersion 30

  • JavaVersion.VERSION_1_8

  • kotlin_version = '1.5.31'

  • com.android.tools.build:gradle:7.0.2

    buildTypes {
     release {
         minifyEnabled true
         shrinkResources true
         proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    
         applicationVariants.all { variant ->
             // Generating apk file for each flavour release build
             variant.outputs.all {
                 outputFileName = "${variant.flavorName}-${variant.versionCode}.apk"
             }
    
             // Generating mapping file for each flavour release build
             if (variant.getBuildType().isMinifyEnabled()) {
                 variant.assembleProvider.get().doLast {
                     def files = variant.getMappingFileProvider().get().getFiles()
                     for (file in files) {
                         if (file != null && file.exists()) {
                             def newName = "mapping-${variant.flavorName}-${variant.versionCode}.txt"
                             def newFile = new File(file.parent, newName)
                             newFile.delete()
                             file.renameTo(newName)
                         }
                     }
                 }
             }
         }
     }
    
Lissettelissi answered 4/10, 2021 at 15:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.