Android一步步实现无痕埋点(4)-------无尽痛苦
在之前全部,已经将无痕埋点transfrom的方面大概梳理了一遍.然后当你升级了gradle7.0之后.
你会发现transfrom有了删除线…他被抛弃了…(连同我的心也一样被抛弃了.)
全网资料真的很少,这还是看到虾哥这边比较新的用法
万恶之始
AsmClassVisitorFactory
,我们来讲讲怎么用吧~拥抱变化吧…
我们实现的仍然是在setOnclick方法下,加入一个我们自己的方法.
Plugin要变.
已经从registerTransform变成了transformClassesWith()
进入其注释可以知道这个方法是去注册一个 asm 类访问者以检测给定范围定义的类。 工厂的一个实例将被实例化并用于为每个类创建访问者。
class NewDoubleTapPlugin : Plugin<Project> {
override fun apply(project: Project) {
//返回插件的类型
val isApp = project.plugins.hasPlugin(AppPlugin::class.java)
println("This is cool , you know -->$isApp")
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
variant.transformClassesWith(PrivacyClassVisitorFactory::class.java,
InstrumentationScope.ALL) {}
variant.setAsmFramesComputationMode(FramesComputationMode.COPY_FRAMES)
println("This is cool , you know -->END????")
}
return
}
companion object {
private const val EXT_NAME = "NewdoubleTab"
}
}
createClassVisitor需要返回ClassVisitor类.
isInstrumentable。判断该类是否需要扫描,这里可以做过滤类的扫描.而ClassData则包含了类的一些信息,可以去看下定义
abstract class PrivacyClassVisitorFactory :AsmClassVisitorFactory<InstrumentationParameters.None>{
override fun createClassVisitor(classContext: ClassContext, nextClassVisitor: ClassVisitor): ClassVisitor {
return PrivacyClassNode(nextClassVisitor)
}
//Is to scan all .class file
override fun isInstrumentable(classData: ClassData): Boolean {
return true
}
}
下面替换的逻辑就不讲了.这里要知道的是ClassNode
它本身是有,interface,method…等属性的
,我们需要找到的目标类都可以在这里进行寻找.
另外 ClassNode 因为是先生成的语法树,所以和一般的ClassVisitor有点小区别,需要在visitEnd方法内调用accept(next)
class PrivacyClassNode(private val nextVisitor: ClassVisitor) :ClassNode(Opcodes.ASM5) {
//ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//ClassVisitor methodFilterCV = new ClassFilterVisitor(classWriter);
//ClassReader cr = new ClassReader(srcClass);
//cr.accept(methodFilterCV, ClassReader.SKIP_DEBUG);
override fun visitEnd() {
super.visitEnd()
val ClassInterface = interfaces
println("privacy transform classNodeName: ${name@this}")
ClassInterface?.forEach { Interface ->
if (Interface == "android/view/View\$OnClickListener") {
methods?.forEach { method ->
// 找到onClick 方法
if (method.name == "" ) {
initFunction(this, method)
}
if (method.name == "onClick" && method.desc == "(Landroid/view/View;)V") {
insertTrack(this, method)
Log.info("Find the method ${method.name} and the desc ${method.desc}")
}
}
}
}
accept(nextVisitor)
}
private fun initFunction(node: ClassNode, method: MethodNode) {
var hasLog = false
node.fields?.forEach {
if (it.name == "textLog") {
hasLog = true
}
}
if (!hasLog) {
node.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "textLog", String.format("L%s;",
"com/kotlin/aop/Buried_point/NewtextLog"), node.signature, null)
val instructions = method.instructions
method.instructions?.iterator()?.forEach {
if ((it.opcode >= Opcodes.IRETURN && it.opcode <= Opcodes.RETURN) || it.opcode == Opcodes.ATHROW) {
instructions.insertBefore(it, VarInsnNode(Opcodes.ALOAD, 0))
instructions.insertBefore(it, TypeInsnNode(Opcodes.NEW, "com/kotlin/aop/Buried_point/NewtextLog") )
instructions.insertBefore(it, InsnNode(Opcodes.DUP))
instructions.insertBefore(it, MethodInsnNode(Opcodes.INVOKESPECIAL, "com/kotlin/aop/Buried_point/NewtextLog",
"" , "()V", false))
instructions.insertBefore(it, FieldInsnNode(Opcodes.PUTFIELD, node.name, "textLog",
String.format("L%s;", "com/kotlin/aop/Buried_point/NewtextLog")))
}
}
}
}
private fun insertTrack(node: ClassNode, method: MethodNode) {
// 判断方法名和方法描述
val instructions = method.instructions
val firstNode = instructions.first
//Insert the code
instructions?.insertBefore(firstNode, VarInsnNode(Opcodes.ALOAD, 0))
instructions?.insertBefore(firstNode, FieldInsnNode(Opcodes.GETFIELD, node.name,
"textLog", String.format("L%s;", "com/kotlin/aop/Buried_point/NewtextLog")))
instructions?.insertBefore(firstNode, MethodInsnNode(Opcodes.INVOKEVIRTUAL, "com/kotlin/aop/Buried_point/NewtextLog",
"textLog", "()V", false))
}
}
我们可以看到与transfrom的区别,我们不需要再去实现增量编译这种东西了。可以说这个东西算是对我们这种使用者能减少更多的学习成本了…当然新的东西没有那么被推广.
但是Android们都被推广Compose了.那使用AsmClassVisitorFactory也是非常合理的把~
不要在意有多长了…重要在于如何入门,然后再一步步的进阶,这些才是真的重要。
Android一步步实现无痕埋点(6)-------AutoService