main.com.xml.guard.tasks.ResGuardTask.kt Maven / Gradle / Ivy
package com.xml.guard.tasks
import com.xml.guard.data.ResDefType
import com.xml.guard.entensions.GuardExtension
import com.xml.guard.model.MappingParser
import com.xml.guard.model.ResInfo
import com.xml.guard.utils.allDependencyAndroidProjects
import com.xml.guard.utils.convertToCamelCase
import com.xml.guard.utils.getLayoutBindingName
import com.xml.guard.utils.isJava
import com.xml.guard.utils.isKt
import com.xml.guard.utils.isXml
import com.xml.guard.utils.javaDirs
import com.xml.guard.utils.lowercaseFirstChar
import com.xml.guard.utils.manifestFile
import com.xml.guard.utils.replaceWords
import com.xml.guard.utils.replaceWordsByPattern
import com.xml.guard.utils.resDirs
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction
import java.io.File
import javax.inject.Inject
open class ResGuardTask @Inject constructor(
private val guardExtension: GuardExtension,
private val variantName: String,
) : DefaultTask() {
init {
group = "guard"
}
private val mappingFile by lazy { project.file(MappingParser.MAPPING_RES) }
private val mapping by lazy {
MappingParser.parseRes(
project,
guardExtension,
mappingFile,
isComparison = true
)
}
@TaskAction
fun execute() {
val androidProjects = allDependencyAndroidProjects(project)
// 1、仅修改资源名,返回本次修改的文件
val resFiles = androidProjects.flatMap { project ->
val resDirs = project.resDirs(variantName)
project.files(resDirs).asFileTree.files
}
val resInfoList = mapping.obfuscateAllRes(resFiles)
// 2、替换 java/kotlin/xml 文件里引用到的资源
if (resInfoList.isNotEmpty()) {
androidProjects.forEach { replaceText(it, resInfoList) }
}
// 3、混淆映射写出到文件
mapping.writeMappingToFile(mappingFile)
}
private fun replaceText(project: Project, resInfoList: List) {
val dirs = mutableListOf()
dirs.add(project.manifestFile())
dirs.addAll(project.resDirs(variantName))
dirs.addAll(project.javaDirs(variantName))
project.files(dirs).asFileTree.forEach fileTree@{ file ->
if (!file.isJava && !file.isKt && !file.isXml) {
return@fileTree
}
var replaceText = file.readText()
resInfoList.forEach { info ->
replaceText = replaceText(file, replaceText, info)
}
file.writeText(replaceText)
}
}
private fun replaceText(rawFile: File, rawText: String, info: ResInfo): String {
return when {
rawFile.isXml -> replaceTextInXml(rawText, info)
rawFile.isJava || rawFile.isKt -> replaceTextInClass(rawText, info)
else -> rawText
}
}
private fun replaceTextInClass(rawText: String, info: ResInfo): String {
val defType = info.defType
if (defType.isBlank() || defType == ResDefType.VALUES.defType) {
return rawText
}
var oldValue = info.rawName
var newValue = info.obfuscateName
var replaceText = rawText.replaceWords(
oldValue = "R.${defType}.${oldValue}",
newValue = "R.${defType}.${newValue}"
)
when (defType) {
ResDefType.LAYOUT.defType -> {
val oldBinding = oldValue.getLayoutBindingName()
val newBinding = newValue.getLayoutBindingName()
replaceText = replaceText.replaceWordsByPattern(oldBinding, newBinding)
}
ResDefType.ID.defType -> {
val oldBindingView = oldValue.convertToCamelCase().lowercaseFirstChar()
val newBindingView = newValue.convertToCamelCase().lowercaseFirstChar()
replaceText = replaceText.replaceWordsByPattern(oldBindingView, newBindingView)
}
ResDefType.STYLEABLE.defType -> {
val rawPrefix = info.rawNamePrefix
val obfuscatePrefix = info.obfuscateNamePrefix
oldValue = "R.${defType}.${rawPrefix}_${oldValue}"
newValue = "R.${defType}.${obfuscatePrefix}_${newValue}"
replaceText = replaceText.replaceWordsByPattern(oldValue, newValue)
}
ResDefType.STYLE.defType -> {
if (oldValue.contains(".")) {
oldValue = "R.${defType}.${oldValue.replace(".", "_")}"
newValue = "R.${defType}.${newValue}"
replaceText = replaceText.replaceWordsByPattern(oldValue, newValue)
}
}
}
return replaceText
}
private fun replaceTextInXml(rawText: String, info: ResInfo): String {
val oldValue = info.rawName
val newValue = info.obfuscateName
return when (info.defType) {
ResDefType.VALUES.defType -> rawText
ResDefType.ID.defType -> rawText
else -> rawText.replaceWords(oldValue, newValue)
}
}
}