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

Solution 1:

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"
                    }
                }
            }
        }
    }

Solution 2:

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"
    }
}

Solution 3:

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.

Solution 4:

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.