j

jhxlx

V1

2022/09/29阅读:23主题:默认主题

Grade Plugin

Grade Plugin

字节码相关

java代码

javap后对应字节码

相关链接 字节码指令详解

Asm介绍

ASM 是一个 Java 字节码操作框架,它能用来动态生成类或者增强既有类的功能。ASM 可以直接生成二进制 class 文件,也可以在类被加载到 Java 虚拟机之前动态改变类行为。

ASM 框架中提供了常见的字节码分析和生成工具,可以快速进行类的生成或分析转换。

在 Android 开发中, Android Gradle 1.5 版本后提供的 Transform 机制, 它允许第三方的 Plugin 插件在 .class 文件打包成 dex 之前进行动态修改,这就为动态修改字节码文件提供了入口,衍生出很多“插桩”的功能,比如埋点、插入日志等。

核心Api

示例代码

val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
val classReader = ClassReader("com.andoter.asm_example.part2.ConvertDemo")
val classVisitor = ChangeVersionVisitor(Opcodes.ASM7, classWriter)
classReader.accept(classVisitor, ClassReader.SKIP_CODE)

1.ClassReader

用于将 Java 类文件转换成 ClassVisitor 能访问的结构。

2.ClassWriter

用于生成符合 JVM 规范的字节码文件,可以单独使用进行生成字节码文件,也可以配合 ClassReader 或 ClassVisitor 适配器进行现有类文件的修改。

3.ClassVisitor

用于访问class文件
主要方法 方法说明:

visit :访问类的头部,其中 version 指类创建时使用的 JDK 的版本,比如 50 代表 JDK1.6、51 代表 JDK1.7。access 代表类的访问权限,比如 public 、private。name 表示类名。signature 表示类的签名,如果类不是泛型或者没有继承泛型类,那么signature 值为空。superName 表示父类的名称。interfaces 表示实现的接口;

visitSource :访问类源文件;

visitModule:访问 Module 模块, Java9 中新增关键字 module用于定义代码和数据的封装体;

visitNestHost:访问嵌套类;

visitOuterClass:访问外部类;

visitAnnotation:访问类的注解;

visitTypeAnnotation:访问类的泛型签名的注解;

visitField:访问类的 Field 字段;

visitMethod:访问类的方法;

visitEnd:结束。

4.MethodVisitor

用于处理方法,获取方法信息

创建一个gradle plugin流程

新建java lib module

需要在resources下创建meta-inf文件夹,并创建对应的plugin.properties,名称一般和报名一致 plugin.properties内定义对应的插件

创建plugin

apply方法中注册transform,transform就是一个个gradle task 按插入顺序执行

*Transform类各个方法介绍

getName() :task名称
getInputTypes() :扫描类型,可设置扫描class和资源文件 getScopes() 设置扫描范围,可设置扫描jar aar,全部工程 isIncremental() 增量扫描
transform(TransformInvocation transformInvocation) 主要处理方法

在transform方法中transformInvocation可以获取编译生成的jar包和文件夹

 Collection<TransformInput> inputs=transformInvocation.getInputs()
        TransformOutputProvider outputProvider=transformInvocation.getOutputProvider()
        if (outputProvider!=null) outputProvider.deleteAll()
        //遍历inputs
        inputs.each {TransformInput input ->
            //遍历directoryInputs
            input.directoryInputs.each { DirectoryInput directoryInput ->
                handleDirectory(directoryInput,outputProvider)
            }

            //遍历jarInputs
            input.jarInputs.each { JarInput jarInputs ->
                handleJarInputs(jarInputs,outputProvider)
            }

        }
 static void handleDirectory(DirectoryInput directoryInput,TransformOutputProvider outputProvider){
        print('=====handleDirectory start')
        if (directoryInput.file.isDirectory()){
            directoryInput.file.eachFileRecurse {File file ->

                def name=file.name
                print('=====eachFileRecurse start'+file.absolutePath)
                print('=====contains Activity'+name.contains("Activity.class"))

                if (checkClassFile(name)){
                    print('----------- deal with "class" file <' + name + '> -----------')
                    ClassReader classReader=new ClassReader(file.bytes)
                    ClassWriter classWriter=new ClassWriter(classReader,ClassWriter.COMPUTE_MAXS)
                    ClassVisitor cv=new LifecycleClassVisitor(classWriter)
                    classReader.accept(cv,ClassReader.EXPAND_FRAMES)
                    byte[] code=classWriter.toByteArray()
                    FileOutputStream fileOutputStream=new FileOutputStream(file.parentFile.getAbsolutePath()+File.separator+name)
                    fileOutputStream.write(code)
                    fileOutputStream.close()
                }
            }
            //Transform扫描的class文件是输入文件(input),有输入必然会有输出(output),处理完成后需要将输入文件拷贝到一个输出目录下去,
            //后面打包将class文件转换成dex文件时,直接采用的就是输出目录下的class文件了。
            //必须这样获取输出路径的目录名称
            def dest= outputProvider.getContentLocation(directoryInput.name,directoryInput.getContentTypes(),directoryInput.scopes,
                    Format.DIRECTORY)
            FileUtils.copyDirectory(directoryInput.file,dest)

        }
    }


LifecycleClassVisitor

 private static class LifecycleClassVisitor extends ClassVisitor{
 
        @Override
        MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            MethodVisitor methodVisitor=super.visitMethod(access, name, desc, signature, exceptions)
            print("calssname ========"+className)
            if ("android/support/v4/app/FragmentActivity" .equals(className) ){

                if ("onCreate".equals(name)){
                    print("LifecycleClassVisitor visit method "+name)
                    methodVisitor=new CreateMethodVisit(methodVisitor)
                }else if ("onDestroy".equals(name)){
                    print("LifecycleClassVisitor visit method "+name)
                    methodVisitor=new DestroyMethodVisit(methodVisitor)
                }
            }
            return methodVisitor
        }
    }

CreatMethodVisit

 void visitCode() {
           super.visitCode()

           mv.visitLdcInsn("Tag")
           mv.visitTypeInsn(Opcodes.NEW,"java/lang/StringBuilder")
           mv.visitInsn(Opcodes.DUP)
           mv.visitMethodInsn(Opcodes.INVOKESPECIAL,"java/lang/StringBuilder","<init>","()V",false);
           mv.visitLdcInsn("----- onDestroy: ")
           mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/StringBuilder","append","(Ljava/lang/String;)Ljava/lang/StringBuilder;",false)
           mv.visitVarInsn(Opcodes.ALOAD,0)
           mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Object","getClass","()Ljava/lang/Class;",false)
           mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Class","getSimpleName","()Ljava/lang/String;",false)
           mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/StringBuilder","append","(Ljava/lang/String;)Ljava/lang/StringBuilder;",false)
           mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/StringBuilder","toString","()Ljava/lang/String;",false)
           mv.visitMethodInsn(Opcodes.INVOKESTATIC,"android/util/Log","i","(Ljava/lang/String;Ljava/lang/String;)I",false)
           mv.visitInsn(Opcodes.POP);



       }

分类:

移动端开发

标签:

Android

作者介绍

j
jhxlx
V1