前言
承接上文: Android 编译优化探索
再最初的版本中需要编译kotlin 才能实现Hack 自定义增量,但是还一个任务同样也及其耗时org.gradle.api.tasks.compile.JavaCompile ,但是此任务不在kotlin 插件,难道我们又要自己编译java 插件?就连鄙人导师都觉得编译kotlin插件很麻烦。于是乎最后决定采用动态修改字节码的方式实现。作者使用javassist 作为字节码编辑器。
JavaCompile创建流程
在android 工程中JavaCompile 的创建是由AGP插件创建,其核心创建核心流程如下
fun <T : Task> TaskContainer.registerTask(
creationAction: TaskCreationAction<T>,
secondaryPreConfigAction: PreConfigAction? = null,
secondaryAction: TaskConfigAction<in T>? = null,
secondaryProviderCallback: TaskProviderCallback<T>? = null
): TaskProvider<T> {
val actionWrapper = TaskAction(creationAction, secondaryPreConfigAction, secondaryAction, secondaryProviderCallback)
return this.register(creationAction.name, creationAction.type, actionWrapper)
.also { provider ->
actionWrapper.postRegisterHook(provider)
}
}
我们最后看看这个
class JavaCompileCreationAction(
private val variantScope: VariantScope,
private val processAnnotationsTaskCreated: Boolean
) : TaskCreationAction<JavaCompile>() {
override val name: String
get() = variantScope.getTaskName("compile", "JavaWithJavac")
override val type: Class<JavaCompile>
get() = JavaCompile::class.java
}
知道大致流程我就可以根据如下思想进行操作:
- 将
JavaCompileCreationAction 的type 替换成自己的JavaCompile类即可
class JavaCompileCreationAction(
private val variantScope: VariantScope,
private val processAnnotationsTaskCreated: Boolean
) : TaskCreationAction<JavaCompile>() {
override val type: Class<JavaCompile>
get() = HackJavaCompile::class.java
}
- 抢在gradle的默认的类加载器之前修改类并强行加载(双亲委托知识)
因次插件会在根工程之后直接启用。
- 处理父加载器引用子加载器的类问题
这个问题也是比较头疼的一个地方,在起初使用jdbc那样委托当前线程的类加载器去加载,然后通过反射去调用子类函数,但是最后发现当前线程类加载器居然是一个较为顶层的类加载器。最后采用所有引用的类都交付顶层类加载器加载,并禁使用lambda表达式(编译器会创建一个新的类,并用子类加载器加载)。
最后解决办法 如以下伪代码
|