Skip to content

Commit

Permalink
[tinker] Support R8 again.
Browse files Browse the repository at this point in the history
  • Loading branch information
tys282000 committed Oct 25, 2021
1 parent 0e583ff commit bc4d6c6
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
*/

package com.tencent.tinker.build.gradle

import org.gradle.api.GradleException
import org.gradle.api.Task
import org.jetbrains.annotations.NotNull

import java.lang.reflect.Field

/**
* For AGP Compatibilities
*
Expand Down Expand Up @@ -74,4 +81,84 @@ class Compatibilities {
static def getAssembleTask(project, variant) {
return project.tasks.findByName("assemble${variant.name.capitalize()}")
}

static def getMultiDexTask(project, variant) {
def capitalizedVariantName = variant.name.capitalize()
def multiDexTask = project.tasks.findByName("multiDexList${capitalizedVariantName}")
if (multiDexTask != null) {
return multiDexTask
}
return project.tasks.findByName("transformClassesWithMultidexlistFor${capitalizedVariantName}")
}

static def getR8Task(project, variant) {
def capitalizedVariantName = variant.name.capitalize()
def r8TransformTask = project.tasks.findByName("transformClassesAndResourcesWithR8For${capitalizedVariantName}")
if (r8TransformTask != null) {
return r8TransformTask
}
return project.tasks.findByName("minify${capitalizedVariantName}WithR8")
}

static def getObfuscateTask(project, variant) {
def capitalizedVariantName = variant.name.capitalize()

// For WeChat internal build tools.
def customProguardTransformTask = project.tasks.findByName("transformClassesWithCustomProguardFor${capitalizedVariantName}")
if (customProguardTransformTask != null && customProguardTransformTask.enabled) {
return customProguardTransformTask
}

def proguardTransformTask = project.tasks.findByName("transformClassesAndResourcesWithProguardFor${capitalizedVariantName}")
if (proguardTransformTask != null && proguardTransformTask.enabled) {
return proguardTransformTask
}

def r8TransformTask = project.tasks.findByName("transformClassesAndResourcesWithR8For${capitalizedVariantName}")
if (r8TransformTask != null && r8TransformTask.enabled) {
return r8TransformTask
}

def r8Task = project.tasks.findByName("minify${capitalizedVariantName}WithR8")
if (r8Task != null && r8Task.enabled) {
return r8Task
}

def proguardTask = project.tasks.findByName("minify${capitalizedVariantName}WithProguard")
if (proguardTask != null && proguardTask.enabled) {
return proguardTask
}

// in case that Google changes the task name in later versions
throw new GradleException(String.format("The minifyEnabled is enabled for '%s', but " +
"tinker cannot find the task. Please submit issue to us: %s", variant.name, TinkerPatchPlugin.ISSUE_URL))
}

static def getInstantRunTask(project, variant) {
return project.tasks.findByName("transformClassesWithInstantRunFor${variant.name.capitalize()}")
}

static def getCollectMultiDexComponentsTask(project, variant) {
return project.tasks.findByName("collect${variant.name.capitalize()}MultiDexComponents")
}

static def getFieldRecursively(ownerClazz, name) {
def currClazz = ownerClazz as Class<?>
while (true) {
try {
def field = currClazz.getDeclaredField(name)
if (!field.isAccessible()) {
field.setAccessible(true)
}
return field
} catch (NoSuchFieldException e) {
if (currClazz != Object.class) {
currClazz = currClazz.getSuperclass()
} else {
throw new NoSuchFieldException("Cannot find field ${name} in ${ownerClazz.getName()} and its super classes.")
}
}
}
// Should not be here.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ import com.tencent.tinker.build.util.Utils
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.jetbrains.annotations.NotNull
import sun.misc.Unsafe

import java.lang.reflect.Field
Expand Down Expand Up @@ -133,7 +131,7 @@ class TinkerPatchPlugin implements Plugin<Project> {
def variantName = variant.name
def capitalizedVariantName = variantName.capitalize()

def instantRunTask = getInstantRunTask(variantName)
def instantRunTask = Compatibilities.getInstantRunTask(project, variant)
if (instantRunTask != null) {
throw new GradleException(
"Tinker does not support instant run mode, please trigger build"
Expand Down Expand Up @@ -199,12 +197,8 @@ class TinkerPatchPlugin implements Plugin<Project> {
boolean proguardEnable = variant.getBuildType().buildType.minifyEnabled

if (proguardEnable) {
TinkerProguardConfigTask proguardConfigTask = mProject.tasks.create("tinkerProcess${capitalizedVariantName}Proguard", TinkerProguardConfigTask)
proguardConfigTask.applicationVariant = variant
proguardConfigTask.mustRunAfter tinkerManifestTask

def obfuscateTask = getObfuscateTask(variantName)
obfuscateTask.dependsOn proguardConfigTask
def obfuscateTask = Compatibilities.getObfuscateTask(project, variant)
obfuscateTask.doFirst new TinkerProguardConfigAction(variant)
}

// Add this multidex proguard settings file to the list
Expand All @@ -220,8 +214,8 @@ class TinkerPatchPlugin implements Plugin<Project> {
// for gradle 3.x gen manifest_keep move to processResources task
multidexConfigTask.mustRunAfter agpProcessResourcesTask

def agpMultidexTask = getMultiDexTask(variantName)
def agpR8Task = getR8Task(variantName)
def agpMultidexTask = Compatibilities.getMultiDexTask(project, variant)
def agpR8Task = Compatibilities.getR8Task(project, variant)
if (agpMultidexTask != null) {
agpMultidexTask.dependsOn multidexConfigTask
} else if (agpMultidexTask == null && agpR8Task != null) {
Expand Down Expand Up @@ -249,7 +243,7 @@ class TinkerPatchPlugin implements Plugin<Project> {
//Maybe it's not a transform task after agp 3.6.0 so try catch it.
}
}
def collectMultiDexComponentsTask = getCollectMultiDexComponentsTask(variantName)
def collectMultiDexComponentsTask = Compatibilities.getCollectMultiDexComponentsTask(project, variant)
if (collectMultiDexComponentsTask != null) {
multidexConfigTask.mustRunAfter collectMultiDexComponentsTask
}
Expand Down Expand Up @@ -325,74 +319,6 @@ class TinkerPatchPlugin implements Plugin<Project> {
tinkerPatchBuildTask.dependsOn Compatibilities.getAssembleTask(mProject, variant)
}

Task getMultiDexTask(String variantName) {
String multiDexTaskName = "multiDexList${variantName.capitalize()}"
String multiDexTaskTransformName = "transformClassesWithMultidexlistFor${variantName.capitalize()}"

def multiDexTask = mProject.tasks.findByName(multiDexTaskName)
if (multiDexTask == null) {
multiDexTask = mProject.tasks.findByName(multiDexTaskTransformName)
}

return multiDexTask
}

Task getR8Task(String variantName) {
String r8TransformTaskName = "transformClassesAndResourcesWithR8For${variantName.capitalize()}"
def r8TransformTask = mProject.tasks.findByName(r8TransformTaskName)
if (r8TransformTask != null) {
return r8TransformTask
}

String r8TaskName = "minify${variantName.capitalize()}WithR8"
def r8Task = mProject.tasks.findByName(r8TaskName)
if (r8Task != null) {
return r8Task
}
}


@NotNull
Task getObfuscateTask(String variantName) {
String proguardTransformTaskName = "transformClassesAndResourcesWithProguardFor${variantName.capitalize()}"
def proguardTransformTask = mProject.tasks.findByName(proguardTransformTaskName)
if (proguardTransformTask != null) {
return proguardTransformTask
}

String r8TransformTaskName = "transformClassesAndResourcesWithR8For${variantName.capitalize()}"
def r8TransformTask = mProject.tasks.findByName(r8TransformTaskName)
if (r8TransformTask != null) {
return r8TransformTask
}

String r8TaskName = "minify${variantName.capitalize()}WithR8"
def r8Task = mProject.tasks.findByName(r8TaskName)
if (r8Task != null) {
return r8Task
}

String proguardTaskName = "minify${variantName.capitalize()}WithProguard"
def proguardTask = mProject.tasks.findByName(proguardTaskName)
if (proguardTask != null) {
return proguardTask
}

// in case that Google changes the task name in later versions
throw new GradleException(String.format("The minifyEnabled is enabled for '%s', but " +
"tinker cannot find the task. Please submit issue to us: %s", variantName, ISSUE_URL))
}

Task getInstantRunTask(String variantName) {
String instantRunTask = "transformClassesWithInstantRunFor${variantName.capitalize()}"
return mProject.tasks.findByName(instantRunTask)
}

Task getCollectMultiDexComponentsTask(String variantName) {
String collectMultiDexComponents = "collect${variantName.capitalize()}MultiDexComponents"
return mProject.tasks.findByName(collectMultiDexComponents)
}

void replaceKotlinFinalField(String className, String filedName, Object instance, Object fieldValue) {
Field field = Class.forName(className).getDeclaredField(filedName)
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@

package com.tencent.tinker.build.gradle.task

import com.tencent.tinker.build.gradle.Compatibilities
import com.tencent.tinker.build.gradle.TinkerBuildPath
import com.tencent.tinker.build.util.FileOperation
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.Task

/**
* The configuration properties.
*
* @author zhangshaowen
*/
public class TinkerProguardConfigTask extends DefaultTask {
class TinkerProguardConfigAction implements Action<Task> {
static final String PROGUARD_CONFIG_SETTINGS =
"-keepattributes *Annotation* \n" +
"-dontwarn com.tencent.tinker.anno.AnnotationProcessor \n" +
Expand All @@ -54,19 +55,18 @@ public class TinkerProguardConfigTask extends DefaultTask {
" *;\n" +
"}\n"

@Internal
def applicationVariant

@Internal
boolean shouldApplyMapping = true;

TinkerProguardConfigAction(variant) {
applicationVariant = variant
}

public TinkerProguardConfigTask() {
group = 'tinker'
@Override
void execute(Task task) {
updateTinkerProguardConfig(task.getProject())
}

@TaskAction
def updateTinkerProguardConfig() {
def updateTinkerProguardConfig(project) {
def file = project.file(TinkerBuildPath.getProguardConfigPath(project))
project.logger.error("try update tinker proguard file with ${file}")

Expand All @@ -79,7 +79,7 @@ public class TinkerProguardConfigTask extends DefaultTask {
String applyMappingFile = project.extensions.tinkerPatch.buildConfig.applyMapping

//write applymapping
if (shouldApplyMapping && FileOperation.isLegalFile(applyMappingFile)) {
if (FileOperation.isLegalFile(applyMappingFile)) {
project.logger.error("try add applymapping ${applyMappingFile} to build the package")
fr.write("-applymapping " + applyMappingFile)
fr.write("\n")
Expand All @@ -100,10 +100,62 @@ public class TinkerProguardConfigTask extends DefaultTask {
fr.write("\n")
}
fr.close()

// Add this proguard settings file to the list
applicationVariant.getBuildType().buildType.proguardFiles(file)
def files = applicationVariant.getBuildType().buildType.getProguardFiles()
injectTinkerProguardRuleFile(project, file)
}

project.logger.error("now proguard files is ${files}")
private void injectTinkerProguardRuleFile(project, file) {
def agpObfuscateTask = Compatibilities.getObfuscateTask(project, applicationVariant)
def configurationFilesOwner = null
def configurationFilesField = null
try {
configurationFilesOwner = agpObfuscateTask
configurationFilesField = Compatibilities.getFieldRecursively(configurationFilesOwner.getClass(), '__configurationFiles__')
} catch (Throwable ignored) {
configurationFilesOwner = null
configurationFilesField = null
}
if (configurationFilesField == null) {
try {
configurationFilesOwner = agpObfuscateTask
configurationFilesField = Compatibilities.getFieldRecursively(configurationFilesOwner.getClass(), 'configurationFiles')
} catch (Throwable ignored) {
configurationFilesOwner = null
configurationFilesField = null
}
}
if (configurationFilesField == null) {
try {
configurationFilesOwner = agpObfuscateTask.transform
configurationFilesField = Compatibilities.getFieldRecursively(configurationFilesOwner.getClass(), 'configurationFiles')
} catch (Throwable ignored) {
configurationFilesOwner = null
configurationFilesField = null
}
}
def agpConfigurationFiles = null
boolean isOK = false
if (configurationFilesOwner != null && configurationFilesField != null) {
try {
agpConfigurationFiles = configurationFilesField.get(configurationFilesOwner)
isOK = true
} catch (Throwable ignored) {
isOK = false
}
}
if (isOK) {
def mergedConfigurationFiles = project.files(agpConfigurationFiles, project.files(file))
try {
configurationFilesField.set(configurationFilesOwner, mergedConfigurationFiles)
def mergedConfigurationFilesForConfirm = configurationFilesField.get(configurationFilesOwner)
println "Now proguard rule files are: ${mergedConfigurationFilesForConfirm.files}"
} catch (Throwable ignored) {
isOK = false
}
}
if (!isOK) {
throw new GradleException('Fail to inject tinker proguard rules file. Some compatibility works need to be done.')
}
}
}

0 comments on commit bc4d6c6

Please sign in to comment.