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

问题描述 投票:23回答:11

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

upd

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

android gradle proguard obfuscation
11个回答
45
投票

更简单的解决方案。

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

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

0
投票

对我有用的完整解决方案

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

7
投票

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

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

文件将以{root}/path/to/your/file名称写入file_name.txt部分。

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

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

您可以定义口味的路径:

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

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


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

}

4
投票

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

3
投票

Sergii Pechenizkyi的很多人帮助我找到了这个好的解决方案。

为了实现每种口味的proguard映射文件的复制,我们可以创建“根”任务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

它像一种魅力。


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,请将其添加到after 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")
                    }
                }
            }
        }
    }
}

在上一个示例中,也将bundleReleaseassembleRelease交换为apk。

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

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


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

NOTE

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

。renameTo()方法需要完整路径,如果您更改路径,我想您可以将File有效地移动到另一个位置。


1
投票

Android Studio Gradle插件版本3.3.0的新增功能(2019年1月)这克服了以前的问题,其中不赞成使用Android 3.0 / Android Gradle插件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)
        }
    }
}

0
投票

Pinhassi的上述解决方案效果很好,并且符合最新的Gradle更改。尽管有一些事情我必须更改:

  1. 模块名称是硬编码的(“ app”),这是不理想的,因为在很多情况下(包括我的)这都不是正确的。最好动态检测模块名称。
  2. 映射文件也仅通过具有向后转义的斜杠(“ \”)来符合Windows文件系统。如果您使用的是* NIX系统(例如Linux或Mac),则需要将其替换为正斜杠(“ /”)
  3. 对.apk文件进行了重命名,以包括项目名称,并在末尾添加了日期/时间戳。

这里是完成的代码:

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 "";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.