前言
Transform API
是 AGP1.5
就引入的特性,主要用于在 Android
构建过程中,在 Class
转Dex
的过程中修改 Class
字节码。利用 Transform API
,我们可以拿到所有参与构建的 Class
文件,然后可以借助ASM
等字节码编辑工具进行修改,插入自定义逻辑。
国github永久回家地址内很多团队都或多或少的用 AGP
的 Transform API
来搞点儿字节码黑科技,比如无痕埋点,耗时统计,方法替换等。但是在AGP7.0
中Transform
已经被标记为废弃了,并且将在AGP8.0
中移除。而AGP8.0
应该会在今年内发字节码布,可以说是已经近在眼前了。所以现在应该是时候了解一下,在Transform
被废弃之后,该怎么适配了。
Transform Action
介绍
Transform API
是由AGP
提供github汤姆的,而Transform Action
则是由Gjavascriptradgitlable
提供。不光是 AGP
需要 Transform
,Java
也需要,所以由 Gradle
来提供统一的 Transform API
也合情合字节码是什么意思理。
这应该APP也是Transform API
被废弃的原因,既然Gradle
已经APP统一提供了API
,AGP
也就没必要自定义一套了。
关于 TransformAction
如何使用,Gradle
官方已github官网登陆入口经提供了很详细的文档–Transforming dependency artifacts on resolution,具体使用可以直接参考文档
AsmClassVisitorFactory
介绍
直接使用Transform Action
的话还是有些麻烦,跟Transform API
一样,需要手动处理增量编译的逻辑。AGP
很贴心的为我们又做了一层封装,提供了AsmClassVisitorFactory
来方便我们使用Transformgithub中文社区 Action
进行ASM
操作。
根据官方的说法,AsmClassVisitoFactory
会带来约18%的性能提升github官网登陆入口,同时可以减少约5倍代码
代码实战
接下来我们利用AGP
的AsmClassVisitorFactory API
,来实现方法执行耗时的插桩。
实现Asgithub下载mClassVisitorFactory
abstract class TimeCostTransform: AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(classContext: ClassContext, nextClassVisitor: ClassVisitor): ClassVisitor {
return TimeCostClassVisitor(nextClassVisitor)
}
override fun isInstrumentable(classData: ClassData): Boolean {
return true
}
}
-
AsmClassVisitorFactory
即创建ClassVisitor
对字节码文件扩展名象的工厂。此接口的实现必须是一个抽象类, -
createClassVisitor
返回我们自定义的ClassVgithub官网登陆入口isitor
,在自定义Visitor
处理完成后,需要传内容传递给javaee下一个Visitapproveor
,因此我们将其放在构造函数中传入 -
isInstrumentable
用javaee于控制我们的自定义Visitor
是否需要处理这个类,通过这个方法可以过滤我们不字节码是什么意思需要的类,加快编译速度
自定义ClassVisitjava环境变量配置or
class TimeCostClassVisitor(nextVisitor: ClassVisitor) : ClassVisitor(Opcodes.ASM5, nextVisitor) {
override fun visitMethod(
access: Int, name: String?, descriptor: String?, signature: String?, exceptions: Array<out String>?
): MethodVisitor {
val methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
val newMethodVisitor =
object : AdviceAdapter(Opcodes.ASM5, methodVisitor, access, name, descriptor) {
@Override
override fun onMethodEnter() {
// 方法开始
if (isNeedVisiMethod(name)) {
mv.visitLdcInsn(name);
mv.visitMethodInsn(
INVOKESTATIC, "com/zj/android_asm/TimeCache", "putStartTime","(Ljava/lang/String;)V", false
);
}
super.onMethodEnter();
}
@Override
override fun onMethodExit(opcode: Int) {
// 方法结束
if (isNeedVisiMethod(name)) {
mv.visitLdcInsn(name);
mv.visitMethodInsn(
INVOKESTATIC, "com/zj/android_asm/TimeCache", "putEndTime","(Ljava/lang/String;)V", false
);
}
super.onMethodExit(opcode);
}
}
return newMethodVisitor
}
private fun isNeedVisiMethod(name: String?):Boolean {
return name != "putStartTime" && name != "putEndTime" && name != "<clinit>" && name != "printlnTime" && name != "<init>"
}
}
这里就跟普通的ASM
操作没什么不同了,主要是apple通过ASM
字节码插桩,在方法的前后插入如下代码,通过计算两者的时间差来得出方法的耗时
fun timeMethod(){
TimeCache.putStartTime("timeMethod") //方法开始插入的代码
Thread.sleep(1000)
TimeCache.putEndTime("timeMethod") //方法结束插入的代码
}
注册Tranjava模拟器sform
老版本的Transform
是注册在AppExtension
中的,新版本则是注册在AndroidComponentsExtension
中
class TimeCostPlugin : Plugin<Project> {
override fun apply(project: Project) {
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
variant.instrumentation.transformClassesWith(TimeCostTransform::class.java,
InstrumentationScope.PROJECT) {}
variant.instrumentation.setAsmFramesComputationMode(
FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
)
}
}
}
- 基于
variant
可实现不同appetite的变种不同的处理逻辑 -
transfogithub汤姆rmClassesWitappearh
通过InstrumentationScope
控制是否需要扫描appstore依赖库代码 -
setAsmFramesComputationMod字节码是什么意思e
可设置不同的栈帧计算模式,具体可查看源码
AsmClassVisitorFactory
的优势
通过以上步骤,一个简单的通过插桩计算方法执行耗时的功能就完成了,这比起老版的Transform API
其实简化了不少,老版本处理增appointment量更新就需要处理一大堆的逻辑。
可以看到我们这里并没有手动处理增量逻辑,这是因为调用AsmClassVisitorFactory
的TransformClassesWithAsmTask
继承自NewIncrementaljavaeeTask
,已经处理了增量逻辑,不需要我们再手动处理了
同时application老版本的Transform
每个Transfrom
各自独立,如果每个Transform
编译构建耗时+10s
,各个Transform
叠在一起,编译耗时就会呈线appear性增长
而新版本可以看出我们也没有手动进行IO
操作,这是因为AsmInstrumentationManagegithub中文官网网页r
中已经做了统一处理,只需要进行一次IO
操作,然后交给ClassVisitor
链表处理,完成后统一交appear给ClaGitHubssWriter
写入
通过这种方式,可以有效地减少IO
操作,这也是新版本API
性能提升的原因
总结
总得来说,由于Transform API
在AGP7.0
已标记为废弃,并且将在AGP8.0
中移除,是时候了解一下如何迁java语言移Transform API
了
而AsmClasappetitesVisitorFactory
相比Transform API
,使用起来更加简单,不需要javascript手动处理增量逻辑,可以专注于字节码插桩操作。同时AsmClassVisitorFactory
通过减少IO
的方式,可以得approach到约20%的性能提升,加快编译速度。
示例代码
本文所有源码可见:github.com/shenzhen201…
参考资料
其实 Gradle Transfogithub永久回家地址rm 就是个纸老虎 —— Gr字节码文件扩展名adle 系列(4)
现在准备好告apple别approachTransform了approve吗? | 拥抱AGP7.0