补充:
开源仓库地址:github.com/HuolalaTech…
原文请访问开源实验室:kymjs.com/code/2024/1…
背景
AGP8 的变更应该很多人都知道了,移除了Transform API
,所以很多 class 操作类的插件代码都需要改了。
TheRouter
在开发的时候就支持了AGP8
,使用的也是Gradle
提供的标准 API。
详细可见官方示例仓库:github.com/android/gra…
project.plugins.withType(AppPlugin::class.java) {
// Queries for the extension set by the Android Application plugin.
// This is the second of two entry points into the Android Gradle plugin
val androidComponents =
project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
// Registers a callback to be called, when a new variant is configured
androidComponents.onVariants { variant ->
val taskProvider = project.tasks.register<ModifyClassesTask>("${variant.name}ModifyClasses")
// Register modify classes task
variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT)
.use(taskProvider)
.toTransform(
ScopedArtifact.CLASSES,
ModifyClassesTask::allJars,
ModifyClassesTask::allDirectories,
ModifyClassesTask::output
)
}
}
问题
这里使用的是toTransform()
这个方法替代老版本的 API,这么做以后有个问题,就是编译速度会非常非常慢,尤其是工程里代码量越大,编译速度越慢,原因我们先看看这个方法的定义。
/**
* Transform the current version of the [type] artifact into a new version. The order in which
* the transforms are applied is directly set by the order of this method call. First come,
* first served, last one provides the final version of the artifacts.
*
* @param type the [ScopedArtifact] to transform.
* @param inputJars lambda that returns a [ListProperty] or [RegularFile] that will be used to
* set all incoming files for this artifact type.
* @param inputDirectories lambda that returns a [ListProperty] or [Directory] that will be used
* to set all incoming directories for this artifact type.
* @param into lambda that returns the [Property] used by the [Task] to save the transformed
* element. The [Property] value will be automatically set by the Android Gradle Plugin and its
* location should not be considered part of the API and can change in the future.
*/
fun toTransform(
type: ScopedArtifact,
inputJars: (T) -> ListProperty<RegularFile>,
inputDirectories: (T) -> ListProperty<Directory>,
into: (T) -> RegularFileProperty)
重点在这一句:last one provides the final version of the artifacts
。这个方法是整个构建最后一步执行,会提供一个最终的输出,并且输出类型是一个 RegularFileProperty
他只能输出一个单独的 File。
这也就意味着你需要把 前期构建的所有产物,包括全部的 jar 依赖、源码编译后的 class 依赖,都在这个Task中聚合到一个产物内返回,这就是耗时的原因。
并且由于需要将所有的 jar 和 class 聚合到一个 jar 内,所以也没办法使用增量编译,这就又进一步拖慢了编译速度。
而对应的老版本操作是,拿到所有的 jar 和 class,需要字节码操作的就做操作,不需要的直接复制一遍到输出路径就可以。很显然,新版本使用的方案还不如旧版本,把所有的class聚合成一个新的jar是很耗时的,而且没办法做增量操作。