美文网首页
gradle-插件无感知(asm)ACTIVITY生命周期

gradle-插件无感知(asm)ACTIVITY生命周期

作者: XII01 | 来源:发表于2020-04-13 23:46 被阅读0次

根据《编译插桩操纵字节码,实现不可能完成的任务》

一、插件步骤

  1. 新建一个Android 工程
  2. 在上面工程中新建一个Android Module项目,类型选择Android Library
  3. 第三步:将Module里的内容删除,只保留build.gradle文件和src/main目录,同时移除build.gradle文件里的内容
  4. 第四步:建立Gradle插件目录
asm_plugin.png

按照上图在main下面建一个groovy目录,在建一个resources/META-INF/gradle-plugins。

5.修改插件.gradle文件

apply  plugin:'groovy'
apply  plugin:'maven'

dependencies{
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compile gradleApi()
    compile localGroovy()
    compile 'com.android.tools.build:gradle:3.3.2'

    //asm
    implementation 'org.ow2.asm:asm:7.1'
    implementation 'org.ow2.asm:asm-commons:7.1'

}

group='wxx.lifecycle.plugin'
version='1.0.0'

uploadArchives{
    repositories{
        mavenDeployer{
            //本地仓库地址
            repository(url:uri('../asm_lifecycle_repo'))
        }
    }
}

在插件的task中找到upload,发布到本地


asm_load.png
  1. new LifeCyclePlugin.groovy
class LifeCyclePlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {
        println '==LifeCyclePlugin=='
        def android=project.extensions.getByType(AppExtension)
        println '------registering AutoTrackTransform------------'
        LifeCycleTransform lifeCycleTransform=new LifeCycleTransform()
        android.registerTransform(lifeCycleTransform)
    }
}
  1. 定义插件名称


    asm_pro.png

    代码如下,就是你插件的地址

implementation-class=com.xxw.plugin.LifeCyclePlugin
  1. app build.gradle 插件配置
buildscript {
    repositories {
        google()
        jcenter()

        maven { url '../asm_lifecycle_repo' }
    }
    dependencies {

        classpath 'wxx.lifecycle.plugin:asm_lifecycle_plugin:1.0.0'
    }
}

8.继承自Transform

class LifeCycleTransform extends Transform {

    /**
     * getName:设置我们自定义的Transform对应的Task名称。
     * Gradle在编译的时候,会将这个名称显示在控制台上。
     * 比如:Task:app:transformClassesWit...
     * @return
     */
    @Override
    String getName() {
        return "LifeCycleTransform"
    }

    /**
     * 在项目中会有各种各样格式的文件,
     * 通过getInputType可以设置LifeCycleTransform接收的文件类型,
     * 此方法返回的类型是Set<QualifiedContent.Conte...
     *
     * @return
     */
    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }
/**
 * 这个方法规定自定义 Transform 检索的范围,具体有以下几种取值:
 *
 *
 * @return
 */
    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.PROJECT_ONLY
    }

    /**
     * 表示当前 Transform 是否支持增量编译,我们不需要增量编译,
     *
     * @return
     */
    @Override
    boolean isIncremental() {
        return false
    }

    /**
     * inputs:inputs 中是传过来的输入流,其中有两种格式,
     * 一种是 jar 包格式,一种是 directory(目录格式)。
     *
     * outputProvider:outputProvider 获取到输出目录,
     * 最后将修改的文件复制到输出目录,这一步必须做,否则编译会报错。
     *
     * @param transformInvocation
     * @throws TransformException
     * @throws InterruptedException
     * @throws IOException
     */
    @Override
    public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        //拿到所有的class文件
        Collection<TransformInput> transformInputs = transformInvocation.inputs
        TransformOutputProvider outputProvider = transformInvocation.outputProvider
        if (outputProvider != null) {
            outputProvider.deleteAll()
        }

        transformInputs.each { TransformInput transformInput ->
            // 遍历directoryInputs(文件夹中的class文件) directoryInputs代表着以源码方式参与项目编译的所有目录结构及其目录下的源码文件
            // 比如我们手写的类以及R.class、BuildConfig.class以及MainActivity.class等
            transformInput.directoryInputs.each { DirectoryInput directoryInput ->
                File dir = directoryInput.file
                if (dir) {
                    dir.traverse(type: FileType.FILES, nameFilter: ~/.*\.class/) { File file ->
                        System.out.println("find class: " + file.name)
                        //对class文件进行读取与解析
                        ClassReader classReader = new ClassReader(file.bytes)
                        //对class文件的写入
                        ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
                        //访问class文件相应的内容,解析到某一个结构就会通知到ClassVisitor的相应方法
                        ClassVisitor classVisitor = new LifecycleClassVisitor(classWriter)
                        //依次调用 ClassVisitor接口的各个方法
                        classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)
                        //toByteArray方法会将最终修改的字节码以 byte 数组形式返回。
                        byte[] bytes = classWriter.toByteArray()

                        //通过文件流写入方式覆盖掉原先的内容,实现class文件的改写。
                        //FileOutputStream outputStream = new FileOutputStream( file.parentFile.absolutePath + File.separator + fileName)
                        FileOutputStream outputStream = new FileOutputStream(file.path)
                        outputStream.write(bytes)
                        outputStream.close()
                    }
                }

                //处理完输入文件后把输出传给下一个文件
                def dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes,
                        directoryInput.scopes, Format.DIRECTORY)
                FileUtils.copyDirectory(directoryInput.file, dest)
            }
        }
    }
}

9.ClassVisitor

public class LifecycleClassVisitor extends ClassVisitor {

    private String className;
    private String superName;


    public LifecycleClassVisitor(ClassVisitor cv) {
        super(Opcodes.ASM5, cv);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        this.className=name;
        this.superName=superName;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        System.out.println("ClassVisitor visitMethod name="+name+",superName"+superName);
        MethodVisitor mv=cv.visitMethod(access,name,descriptor,signature,exceptions);

        if (superName.endsWith("AppCompatActivity")){
            if (name.startsWith("onCreate")){
                return new LifeCycleMethodVisitor(mv,className,name);
            }
        }

        return mv;
    }

    @Override
    public void visitEnd() {
        super.visitEnd();
        System.out.println("visitEnd");
    }
}

10.MethodVisitor


public class LifeCycleMethodVisitor extends MethodVisitor {
    private String className;
    private String methodName;
    public LifeCycleMethodVisitor(MethodVisitor methodVisitor,String className,String MethodName) {
        super(Opcodes.ASM5, methodVisitor);
        this.className=className;
        this.methodName=methodName;
    }

    @Override
    public void visitCode() {
        super.visitCode();
        super.visitCode();
        System.out.println("MethodVisitor visitCode------");

        mv.visitLdcInsn("TAG");
        mv.visitLdcInsn(className + "---->" + methodName);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "android/util/Log", "i", "(Ljava/lang/String;Ljava/lang/String;)I", false);
        mv.visitInsn(Opcodes.POP);
    }
}

运行activity查看结果


asm_result.png

相关文章

  • gradle-插件无感知(asm)ACTIVITY生命周期

    根据《编译插桩操纵字节码,实现不可能完成的任务》 一、插件步骤 新建一个Android 工程 在上面工程中新建一个...

  • 学习自定义Gradle插件2

    前序步骤参考链接:学习自定义gradle插件 使用 ASM,插入字节码到 Activity 文件 1.在 asm_...

  • 二、Lifecycle

    使用生命周期感知组件处理生命周期 生命周期感知组件可以在其他组件(例如 activity 和 fragment)的...

  • Lifecycle 生命周期源码解析

    目录: 什么生命周期 什么是生命周期感知型组件 Activity是如何把生命周期传给生命周期感知组件的 生命周期 ...

  • 【Android Jetpack】- Lifecycles(源码

    简介 用于感知Activity和Fragment生命周期。然后在不同生命周期执行不同的操作。 Activity中的...

  • Lifecycles原理

    Lifecycles 作用:管理 Activity 和 Fragment 生命周期既然可以感知activity和f...

  • 横竖屏切换---避免Activity销毁重建

    基本生命周期 Activity之间跳转 Activity中弹出AlertDialog 对Activity生命周期无...

  • Jetpack-Lifecycle

    Lifecycle概述 Lifecycle是生命周期感知型组件,可感知组件(如 Activity、 Fragmen...

  • jectpack之Lifecycle入门

    lifecycle是什么 lifecycle是一个生命周期感知组件 它可以感知Fragment/Activity的...

  • Jetpack-Lifecycle

    使用生命周期感知型组件处理生命周期 生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fra...

网友评论

      本文标题:gradle-插件无感知(asm)ACTIVITY生命周期

      本文链接:https://www.haomeiwen.com/subject/uhfamhtx.html