如何在Android项目的gradle中更改proguard映射文件名

时间:2015-03-09 17:48:22

标签: android gradle proguard obfuscation

我有基于gradle的android项目,我想在为我的构建生成后更改mapping.txt文件名。怎么办呢?

UPD

如何在build.gradle中完成?由于我可以访问我的口味和其他僵硬,我想根据flavor / build变体版本创建映射文件名。

12 个答案:

答案 0 :(得分:43)

更简单的解决方案。

applicationVariants.all { variant ->
        if (variant.getBuildType().isMinifyEnabled()) {
            variant.assemble.doLast {
                copy {
                    from variant.mappingFile
                    into "${rootDir}/proguardTools"
                    rename { String fileName ->
                        "mapping-${variant.name}.txt"
                    }
                }
            }
        }
    }

答案 1 :(得分:7)

在proguard-rules.pro文件中使用此命令:

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

该文件将使用{root}/path/to/your/file名称部分file_name.txt编写。

如果您想为不同的口味设置不同的设置,可以为它们定义许多proguard规则

我发现了另一个想法,但我不确定这是正确的方法。

您可以在风格中定义路径:

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

接下来您可以在$asseble{variant.name.capitalize()}任务之前定义新任务,如下所示:

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

并在脚本${root}/utils/test.bash中 - 您可以修改proguard-rules.pro

但我认为存在更好的解决方案。

答案 2 :(得分:4)

由于上次更新variant.mappingFile不再可用。 (我使用ProGuard 4.7版,AndroidStudio 2.0)

这是我的build.gradle文件的一部分:

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

}

答案 3 :(得分:4)

这是igorpst's answer的变体,但重命名mapping.txt以匹配apk的名称,包括应用版本名称。我将此与代码相结合,将APK命名为this answer中所述的版本号。我不得不窥探gradle源代码以找到$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")
            }
        }
    }
}

答案 4 :(得分:4)

截至今天(2020年5月)使用variant.mappingFile的旧解决方案在新的Android Gradle插件(Android Studio) 3.6 及更高版本中不再起作用

相反,variant.mappingFile返回null,并在日志中显示以下内容:

警告:API'variant.getMappingFile()'已过时,并已替换为'variant.getMappingFileProvider()'。

我正在分享使用新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)
                }
            }
        }
    }

请注意,由于我们使用的是DexGuard,因此未使用 variant.getBuildType()。isMinifyEnabled()

上面的代码使映射文件的名称与apk的文件名匹配。

以防万一,如果您需要更改apk名称-可以使用以下内容:

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

答案 5 :(得分:3)

帮助我找到这个好解决方案的Sergii Pechenizkyi非常感谢。

为每种口味实现proguard映射文件的复制,我们可以创建&#34; root&#34;任务copyProguardMappingTask和每种风味的动态任务数

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

之后我们应该在组装项目后运行此任务。我使用jenkins,我的任务选项看起来像

gradle clean assembleProjectName copyProguardMapping

它就像一个魅力。

答案 6 :(得分:3)

variant.assemble现在已弃用,建议的解决方案包含以前的修改:

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

如果使用应用捆绑包(aab)而不是apk,请将其添加到android部分的 之后:

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

在上一个示例中,也将bundleRelease换为assembleRelease换成apk。

更新:但是,如果您尝试直接在手机上构建常规调试,则最后一种方法不起作用。错误:

无法获得类型为org.gradle.api.Project的项目':app'的未知属性'bundleRelease'。

答案 7 :(得分:2)

所有这些答案都使用了复制来重命名文件。 我并不想移动文件,我只是想改变它的名字,记住构建类型和风格。

我基于这里其他海报的代码并稍微改了一下。 由于Minify可能是假的,但仍然使用proguard,我只是检查文件是否存在。

以下代码完成了这一点。

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

注意

您也可以使用此代码移动文件。

<。> .renameTo()方法需要一个完整的路径,如果你改变路径,我认为你有效地将文件移动到另一个地方。

答案 8 :(得分:2)

对我有用的完整解决方案

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

答案 9 :(得分:1)

Android Studio Gradle插件版本3。3。0(2019年1月)的新功能 这克服了以前的问题,其中Android 3.0 / Android Gradle Plugin 3.0已弃用BuildType.isMinifyEnabled()且gradle插件已弃用 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)
        }
    }
}

答案 10 :(得分:0)

上面的Pinhassi解决方案效果很好,它符合最新的Gradle变化。虽然我必须改变一些事情:

  1. 模块名称是硬编码的(“app”),这是不理想的,因为在很多情况下(包括我的)不会是真的。最好动态检测模块名称。
  2. 映射文件也只能通过反向转义斜杠(“\”)符合Windows文件系统。如果您使用的是Linux或Mac等* NIX系统,则需要使用前向非转义斜杠(“/”)替换那些
  3. 更改了.apk文件的重命名以包含项目名称,并在最后添加了日期/时间戳。
  4. 以下是完成的代码:

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

答案 11 :(得分: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"
                    }
                }
            }
        }
    }
}