Как изменить имя файла отображения Proguard в Gradle для проекта Android
У меня есть Android-проект, основанный на Gradle, и я хочу изменить имя файла mapping.txt после его создания для моей сборки. Как это можно сделать?
обн
Как это можно сделать в build.gradle? Так как у меня есть доступ к моим версиям и другим жестким файлам, я хотел бы создать имя файла сопоставления на основе варианта варианта flav /build.
13 ответов
Большое спасибо 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
}
}
}
после этого мы должны выполнить эту задачу после сборки нашего проекта. Я использую Дженкинс, и мой вариант задач выглядит так
gradle clean assembleProjectName copyProguardMapping
Отлично работает.
Более простое решение.
applicationVariants.all { variant ->
if (variant.getBuildType().isMinifyEnabled()) {
variant.assemble.doLast {
copy {
from variant.mappingFile
into "${rootDir}/proguardTools"
rename { String fileName ->
"mapping-${variant.name}.txt"
}
}
}
}
}
На сегодняшний день (май 2020 г.) прежнее решение, использующее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)
}
}
}
}
Обратите внимание, что вариант.getBuildType(). IsMinifyEnabled() не используется, поскольку мы используем DexGuard.
В приведенном выше коде имя файла сопоставления совпадает с именем файла apk.
На всякий случай, если вам нужно изменить имя apk - можно использовать следующее:
android {
defaultConfig {
//resulting apk will looks like: "archive base name" + -<flavour>-<buildType>.apk
archivesBaseName = "$applicationId-$versionName"
}
}
Используйте эту команду в вашем файле 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
,
Но я думаю, что существуют лучшие решения.
С момента последнего обновления option.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")
}
}
}
}
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
для apks в последнем примере тоже.
Обновление: Однако последнее не сработает, если вы попытаетесь создать нормальную отладку прямо на вашем телефоне. Ошибка:
Не удалось получить неизвестное свойство "bundleRelease" для проекта ": приложение" типа org.gradle.api.Project.
Это вариант ответа igorpst, но переименовывается в mapping.txt, чтобы он точно совпадал с именем apk, включая имя версии приложения. Я объединил это с кодом, чтобы назвать 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")
}
}
}
}
Полное решение, которое сработало для меня
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")
}
}
}
Предыдущий ответ работал прекрасно для меня, пока Android 3.0/Android Gradle Plugin 3.0 не устарел BuildType.isMinifyEnabled()
,
Я разработал следующее решение, которое не использует устаревший метод:
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)
}
}
}
Все эти ответы использовали копию, чтобы переименовать файл. Однако я не хотел перемещать файл, я просто хотел изменить его имя, учитывая тип сборки и ее вид.
Я основывался на коде с других постеров и немного его изменил. Так как 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() ожидает полный путь. Если вы измените путь, я бы предположил, что вы фактически переместите файл в другое место.
Вот решение, которое мне помогает:
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) } } } } } }
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"
}
}
}
}
}
}
Приведенное выше решение Pinhassi прекрасно работает и соответствует последним изменениям Gradle. Есть пара вещей, которые мне пришлось изменить:
- Имя модуля жестко закодировано ("приложение"), что не является идеальным, поскольку во многих случаях (включая мой) это не соответствует действительности. Лучше динамически определять имя модуля.
- Файл сопоставления также соответствует только файловой системе Windows, имея косые черты в обратном порядке ("\"). Если вы работаете в системе *NIX, такой как Linux или Mac, вам нужно заменить их на прямые не экранированные слеши ("/")
- Немного изменилось переименование файла.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 "";
}
}