How to change the proguard mapping file name in gr

2019-01-11 10:24发布

问题:

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.

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


回答2:

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.



回答3:

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

}


回答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")
            }
        }
    }
}


回答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.



回答6:

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.



回答7:

An earlier answer was working great for me until Android 3.0/Android Gradle Plugin 3.0 deprecated BuildType.isMinifyEnabled().

I developed the following solution which doesn't use the deprecated method:

applicationVariants.all { variant ->
    variant.assemble.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)
        }
    }
}


回答8:

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


回答9:

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