在以前的agp版本中,我们可以onVarint回调中直接获取到任意task的provider,这让我们可以很轻松的插入一个任务到android的编译过程中
在8.0+以后 这个方案失效了, 这个会导致我们很多自定义的插件无法执行,举个例子,在编译中将png和jpg 压缩成webp 来缩减包大小是通用方案,但这个方案的第一步 是 你得在mergeRes任务之后 processRes任务之前 处理好这些 res文件
下面介绍一种简单的方案 可以在8.0+ 上实现 这个任务插入的过程
先拿到provider
class CreationAction(private val appVariant: ApplicationVariant) {
fun extractMergedRes(): Provider<Directory> {
return appVariant.getArtifactsImpl()
.get(InternalArtifactType.MERGED_RES)
}
}
fun ApplicationVariant.getArtifactsImpl() = getApplicationVariantImpl().artifacts
fun ApplicationVariant.getApplicationVariantImpl(): ApplicationVariantImpl {
return when (this) {
is ApplicationVariantImpl -> {
this
}
is AnalyticsEnabledApplicationVariant -> {
this.delegate as ApplicationVariantImpl
}
else -> {
throw UnsupportedOperationException("Can not convert $this to ApplicationVariantImpl.")
}
}
}
然后处理varint和provider的对应关系
val resVariantMap = mutableMapOf<String, Provider<Directory>>()
val androidComponents = target.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
resVariantMap[variant.name] = CreationAction(variant as ApplicationVariant).extractMergedRes()
}
最后利用doLast来处理
val regex = "^merge|Resources$".toRegex()
target.gradle.taskGraph.whenReady {
allTasks.forEach {
// 先找到mergeResource这个任务
if (it.name.startsWith("merge") && it.name.endsWith("Resources")) {
it.doLast {
// 任务的完整名称中间就是varint的名称
val varintKey = regex.replace(it.name, "")
// 我们拿到varint的名称就可以去拿到这个varint对应的mergeResource的路径了
val result = resVariantMap[varintKey]
println("{result!!.get().asFile.absolutePath}")
result.get().asFileTree.files.forEach { info->
// 在这里能拿到全部res下的文件 自行处理你的需求即可
println("info info = ${info.name}")
}
}
}
整体方案虽然不够优雅 但是基本能完成适配的需求