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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值