ProGuard writes the mapping file under the build directory of the project. Under normal circumstances all files and directories under the build dirs are excluded from version control. That is a bit of an issue if you want to be able to save that file with every release build. I always forget to this manually. So, let’s do that at build time with Gradle and while we are at it, we might as well rename our apk file, so we don’t have to do that manually either.
Here is the relevant code to put in our build.gradle file:
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.all { output ->
def fullName = output.outputFile.name
projectName = fullName.substring(0, fullName.indexOf('-'))
// ${variant.name} has the value of "paidRelease"
outputFileName = new File((String) output.outputFile.parent, (String) outputFileName.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 "";
}
}
The above code was updated for the new Android Studio 3.0 and Gradle 3.0.
The new Gradle introduces some changes and the output.outputFile is now a read only property. So, you cannot change it starting with Gradle 3. You will get the following error:
“Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=release, filters=[]}}…”
Here are the changes:
old:
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"))
}
new:
variant.outputs.all { output ->
def fullName = output.outputFile.name
projectName = fullName.substring(0, fullName.indexOf('-'))
// ${variant.name} has the value of "paidRelease"
outputFileName = new File((String) output.outputFile.parent, (String) outputFileName.replace(".apk", "-v${variant.versionName}-${formattedDate}.apk"))
}