• lancet的维护--涉及gradle升级,plugin开发,asm使用


    一、agp升级到7.2.1 gradle7.3.3时lancet不好使了,dexbuild task报错

    💡 Tips:之前的lancet版本在gradle7.3.2时还是好使的,并查阅了7.3.3的升级文档并未发现异常

    • 排除了google bug的可能,排除了lancet注解框架的问题
    • 怀疑是7.3.3 jvm的参数改动,导致asm编译class时出现了api问题

    二、修改lancet源码,debug plugin查看问题

    💡 Tips:建议开两个工程,一个用来debug,一个用来给插件打包

    1. 将插件代码放在buildSrc下,因为buildSrc是默认module并且优先级最高,优先编译

    • 当插件是多module时建议合成一个,方便开发调试
    • 依赖问题:agp 7.2.1以后buildscript要放在plugins的前面,java插件变更为java-library
    • 当用buildSrc时插件不需要在项目级build中声明classpath,module引用时可以直接import 插件的class,然后再apply 代码如下
    plugins {
        id 'com.android.application'
        id 'org.jetbrains.kotlin.android'
    }
    import me.ele.lancet.plugin.LancetPlugin
    apply plugin: LancetPlugin

    2.插件的基本格式

    • 判断gradle运行环境,当为android的项目时注册插件
    public class LancetPlugin implements Plugin<Project> {
    
        @Override
        public void apply(Project project) {
            if (project.getPlugins().findPlugin("com.android.application") == null
                    && project.getPlugins().findPlugin("com.android.library") == null) {
                throw new ProjectConfigurationException("Need android application/library plugin to be applied first", (Throwable) null);
            }
    
            BaseExtension baseExtension = (BaseExtension) project.getExtensions().getByName("android");
    
            LancetExtension lancetExtension = project.getExtensions().create("lancet", LancetExtension.class);
            baseExtension.registerTransform(new LancetTransform(project, lancetExtension));
        }
    }
    • 可以用自带工具生成插件信息

    • 存在metainfo重复没有覆盖策略的问题,需要在build中添加如下代码
    jar{
        from('src/main/java'){
            include 'src/main/resources/META-INF/gradle-plugins/me.ele.lancet.properties'
        }
    }

    3.debug插件

    • 在edit configurations中创建remote jvm debug,获取argumments for jvm

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

    • 将上述参数中的suspend改为=y,然后将参数设置到要debug的gradle指令的vm op中

    • 然后愉快的debug就可以了

    4.经过debug发现插件正常运行,未发现问题,因此怀疑jvm asm的问题

    • 当前插件asm用的6.0beta,官网已经升级到了9.3(支持gradle7.4.2),并且结构发生了变化

    三、asm调试

    1.添加神器asmplugin,这样build出来的transforms class就能看到里面的结构

    2.idea安装插件java decompiler,这样可以直接看到class直译过来的代码,可以对比hook代码查找差异

    3.经对比发现dex报错是因为hook的代码片段被asm编译的不对,无法正常运行

    • 分析插件代码找到asm插入代码的地方,修改插入的代码
    • 插件主要对自定义的Origin.call() callVoid()进行了参数替换,替换成引用代码的对象
    • 流程如下,通过注解找到插入的方法,找到含有call的指令并进行remove,这种情况添加自定义的opcode,当asm遇到对应的code时添加自己创建的方法
    • 发现asm setOpcode新的api只收受jvm的指令code,不在支持自定义,所以导致asm生成的class编译失败
    • 尝试不同jvm code,对比生成的class,最终将code定义为Opcodes.INVOKEDYNAMIC

    四、发布改好的插件

    • 将buildSrc模块改为自定义模块,并在setting中注册
    • 引用maven-publish,按照常用方式即可将生成的jar上传

    五、总结

    • 大厂设计的框架还是很稳定,主要是随着技术升级导致的api不兼容,以后主要从api入手
    • 刚接手问题时确实无从下手,新版本文档少,大家发出的遇到问题的技术贴也少,这时只能查官方文档论坛,翻墙google,提issue,尽可能的查看日期较新的文章和issue
    • 更换思路,不要一直纠结在一个问题点上,跳出来换个思路;或者看不懂时随便改改你觉得重要的地方看看结果如何变化,这样去解决问题;虽然不理解代码,但是尝试总是能帮你更好的理解

    参考以下文章

    • gradle系列

    Gradle Transform 就是个纸老虎 —— Gradle 系列(4)

    手把手带你自定义 Gradle 插件 —— Gradle 系列(2)

    • asm系列

    Java ASM详解:ASM库使用

    Java ASM详解:MethodVisitor与Opcode(一)基本操作与运算

    Java ASM详解:类的结构(二)

    AOP系列01:利用ASM动态创建Class

  • 相关阅读:
    木舟0基础学习Java的第十六天(异常,分类,自定义异常,注意事项)
    Vue鼠标右键画矩形和Ctrl按键多选组件
    计算机网络(IP/TCP网络分层)
    Unbuntu-18-network-issue
    DaemonSets On K8s
    单元测试效率优化:为什么要对程序进行测试?测试有什么好处?
    《Linux图形驱动与桌面》之DMA-FENCE
    2022最新Java后端面试题(带答案),重点都给画出来了!你不看?
    通过python 获取当前局域网内存在的IP和MAC
    7-4 USB接口的定义 (10分)
  • 原文地址:https://blog.csdn.net/qq_21001399/article/details/125444881