Reputation: 1115
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.
Upvotes: 29
Views: 18500
Reputation: 71
Here is solution that helps me:
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)
}
}
}
}
}
}
Upvotes: 0
Reputation: 9823
For Android Studio Gradle Plugin Version 4.1.0 and newer (since about May 2020)
This version fixes the following warning:
WARNING: API 'variant.getMappingFile()' is obsolete and has been replaced with 'variant.getMappingFileProvider()'.
applicationVariants.all { variant ->
variant.assembleProvider.get().doLast {
def mappingFileProvider = variant.getMappingFileProvider().get()
if (mappingFileProvider != null) {
try {
def mappingFiles = mappingFileProvider.getFiles()
for (mappingFile in mappingFiles) {
if (mappingFile != null && mappingFile.exists()) {
def newMappingFileName = "$archivesBaseName-$variant.baseName-$mappingFile.name"
project.logger.lifecycle("Renaming '${mappingFile.name}' to '${newMappingFileName}'")
def newMappingFile = new File(mappingFile.parent, newMappingFileName)
newMappingFile.delete()
mappingFile.renameTo(newMappingFile)
}
}
} catch (Exception ignored) {
project.logger.lifecycle("No mapping files found to rename")
}
}
}
}
For Android Studio Gradle Plugin Version 3.3.0 (January 2019) through about May 2020
This overcomes previous issues where Android 3.0/Android Gradle Plugin 3.0 deprecated BuildType.isMinifyEnabled()
and the gradle plugin deprecated 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)
}
}
}
Upvotes: 2
Reputation: 566
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"
}
}
Upvotes: 8
Reputation: 79
A complete solution that worked for me
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")
}
}
}
Upvotes: 2
Reputation: 9823
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")
}
}
}
}
Upvotes: 4
Reputation: 11909
variant.assemble
is now deprecated, suggested solution incorporating previous modifications:
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)
}
}
}
If using app bundle (aab) instead of apk, add this to after the android section:
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")
}
}
}
}
}
}
Swap bundleRelease
for assembleRelease
for apks in the last example too.
Update: However that last doesn't work if you try and build a normal debug directly to your phone then. Error:
Could not get unknown property 'bundleRelease' for project ':app' of type org.gradle.api.Project.
Upvotes: 4
Reputation: 1296
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.
Upvotes: 2
Reputation: 81
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"
}
}
}
}
}
}
Upvotes: 0
Reputation: 2326
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:
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 "";
}
}
Upvotes: 0
Reputation: 15573
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")
}
}
}
}
Upvotes: 4
Reputation: 1240
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"
}
}
}
}
}
Upvotes: 49
Reputation: 1115
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.
Upvotes: 5
Reputation: 12365
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.
Upvotes: 7