[Android开发]gradle插件开发中使用toTransform编译提速

前言

相信大家在适配AGP8.0以上gradle插件时使用了官方方案(Android Gradle插件更新)的如下API

kotlin 复制代码
variant.artifacts.forScope(ScopedArtifacts.Scope.ALL)
    .use(taskProvider)
    .toTransform(
        ScopedArtifact.CLASSES,
        ModifyClassesTask::allJars,
        ModifyClassesTask::allDirectories,
        ModifyClassesTask::output,
    )

使用过这个api的小伙伴应该都有同样的感受,就是去插入注册代码的时候虽然也简单方便了许多,但同时引发了新的问题,那就是最终有一个前缀名为 dexBuilder 的任务每次打包时时间都会变得非常的长,导致影响开发效率,不用这个api就没事。

看过官方文档的也发现了还有以下的一个新方式,可以避免dexBuilder任务时间变长的问题,但是同时也引发了一个新的问题,就是这是一个一边遍历一边修改字节码的方法,任务结束后也就只是相当于遍历了一次所有代码,根本没有机会去修改想要修改的代码

kotlin 复制代码
androidComponents {
      onVariants(selector().all(), {
          instrumentation.transformClassesWith(AsmClassVisitorFactoryImpl.class,
                                               InstrumentationScope.Project) { params ->
              params.x = "value"
          }
          instrumentation.setAsmFramesComputationMode(
              COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
          )
      })
  }

相信不能使用 transformClassesWith 的小伙伴都是有一个共同的需求那就是:都是需要遍历最终打包到 apk 的所有类,然后才可以修改字节码。到这貌似进入了一个死胡同,有着全盘扫描的api会使打包变慢,不变慢的api又不能扫描完所有的代码再去修改字节码。

解决思路

既然不可避免的要使用 toTransform 那就踏踏实实的用,好在我们知道了变慢的原因是名为 dexBuilder 的任务变得时间很长,那么我们就去解决它不就好了吗?

首先想想为什么这个任务时间很长,toTransform 的输出是一个 jar 文件,相信这一点你是知道的,原因就在于apk的所有的代码都被打入了这一个 jar 文件,dexBuilder 就是将 jar 包转化为 dex 文件的任务,紧接着基本就是打包为apk了。

我们每次改完哪怕一点点的代码都会生成这一个jar包,就导致 dexBuilder 每次都要处理 所有的代码 ,那么我们把代码拆分成多个 jar 包不就好了吗?是的,就是这样,这才是关键所在,说起来简单,做起来就难了......

相信看到这你会说:

"我也想到过这么多,但是 output 设置成文件夹就会报错"

还有人说:

"我把 output 设置成文件夹不报错了,但是最终打包的apk没有代码了"

都说的不错,但是大家说的其实已经接近真相了,只要成功把 output 设置成文件夹,并能把代码拆分多个jar包分别写入就成功了一大半了,无非就是打包的apk没有了代码,其实原因就在于设置成的文件夹 dexBuilder 任务无法识别,我们只要让它识别不就好了吗?哈哈,看到这,是不是很激动了

dexBuilder 任务的类是 DexArchiveBuilderTask,我们获取到它去改变他的输入参数就好了,上代码

kotlin 复制代码
project.tasks.withType(DexArchiveBuilderTask::class.java).forEach { dexTask ->
    dexTask.projectClasses.setFrom(files)
}

这个方法会自动识别传进来的jar包是否需要重新转为dex,另外设置这个代码的时机很重要,我们不可以在 gradle 的配置阶段(就是有向无环图那个阶段)去调用 setFrom 因为此时 toTransform 的任务还没生成所有的 jar 包,所以我们需要动态的去修改,这个修改时机就是 toTransform 任务完成的时候去设置它。

下边是修改 output 的配置方法

kotlin 复制代码
@get:OutputDirectory
abstract val hideOutputDir: RegularFileProperty

结束语

上述解决方案应该是当前最好的解决方案了,里边还有一些细节,例如我们应该如何生成多个jar包?如何只修改修改了代码的jar包,更多细节可以看到的开源项目:FastTransform

相关推荐
程序员爱钓鱼4 分钟前
Node.js 编程实战:测试与调试 —— 日志与监控方案
前端·后端·node.js
Mapmost13 分钟前
数字孪生项目效率翻倍!AI技术实测与场景验证实录
前端
lizhongxuan16 分钟前
Manus: 上下文工程的最佳实践
算法·架构
小酒星小杜17 分钟前
在AI时代,技术人应该每天都要花两小时来构建一个自身的构建系统-Input篇
前端·程序员·架构
Cache技术分享25 分钟前
290. Java Stream API - 从文本文件的行创建 Stream
前端·后端
陈_杨27 分钟前
前端成功转鸿蒙开发者真实案例,教大家如何开发鸿蒙APP--ArkTS 卡片开发完全指南
前端·harmonyos
_李小白28 分钟前
【Android FrameWork】第四十九天:SystemUI
android
Mr -老鬼29 分钟前
移动端跨平台适配技术框架:从发展到展望
android·ios·小程序·uni-app
小杨同学4934 分钟前
C 语言实战:枚举类型实现数字转星期(输入 1~7 对应星期几)
前端·后端
陈_杨35 分钟前
前端成功转鸿蒙开发者真实案例,教大家如何开发鸿蒙APP--ArkTS 卡片刷新机制
前端·harmonyos