gradle插件分享-手把手教你写gradle插件

写在前面:

  • 在基础熟练的基础上,完全可以考虑基于Booster、ByteX等框架来开发,效率应该会高一些。

  • 修改字节码的插件不止asm一个,还有javaassist等,可以多做一些尝试,按照需求选择适合自己项目的。

  • 本次分享的目的旨在展示gradle插件开发的过程、思路、需要的基础、遇到问题后如何分析等,核心在于打好基础。

整体目标:hook应用内所有的手势,还原成操作手势事件,交由服务端进行轨迹还原等操作。

核心任务拆分

核心任务聚焦:拿到应用内所有手势事件的MotionEvent

关键节点:

事件分发-何处hook
字节码基础-如何修改
apk构建过程-何时修改
使用gradle-如何开发插件
MotionEvent处理:自行将原始的MotionEvent合并成为我们常用的事件序列。

事件分发-何处hook

hook点:activity的时机比较合适

  • 触摸事件最终都会交由Acivity来处理

  • Acivity#dispatchTouchEvent方法负责分发给对应的view进行处理

    • Activity -> PhoneWindow -> DecorView -> ViewGroup -> View

最终做到的如下所示:


@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    TouchEventDispatcher.dispatchTouchEvent(MainActivity.this, ev);
    return super.dispatchTouchEvent(ev);
}

适配不同版本的Activity

  • 对特定的根Activity做处理,这样可以对其子类进行处理,可以覆盖所有的Activity。

  • AppCompatActivity:

v7_AppCompat_Activity: "android/support/v7/app/AppCompatActivity";
androidx_AppCompat_Activity: "androidx/appcompat/app/AppCompatActivity";

字节码基础-如何修改

  • 字节码本质:二进制文件

    • jvm校验通过的就是合法的字节码文件,不问来源。

    • 比如你通过文本编辑器写的字节码文件,只要符合字节码格式,那也是合法的字节码文件。

  • 字节码格式:

111.png
  • 查看Java字节码内容的几种方式

  • jvm指令集

  • 如何修改字节码- 借助ASM等工具.

    • ASM官网

    • 1、ClassReader:对class文件进行读取与解析;

    • 2、ClassWriter:参与字节码修改,并将修改后的字节码内容以字节流的形式返回。

    • 3、使用ClassNode与MethodNode配合判断:目标Class中如果没有目标方法,就使用ClassWriter + MethodVisitor,无中生有的增加目标方法(dispatchTouchEvent)的默认实现。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }
    
    • 2、ClassVisitor和MethodVisitor:找到目标Class(CompatActivity的子类),如果存在目标方法(dispatchTouchEvent),则直接在方法入口处增加我们的工具方法调用。
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        TouchEventDispatcher.dispatchTouchEvent(MainActivity.this, ev);
        return super.dispatchTouchEvent(ev);
    }
    
    • class会遍历两遍。

apk构建过程-何时修改

  • 整体架构图
  • 详细的图:


    333.png

使用gradle-如何开发插件

  • 使用groovy语言开发,面向Java平台。也可以kotlin开发(趋势)。

  • Project基础概念

    • Project

    • 每一个 build.gradle 文件都会转换成一个 Project 对象。在 Gradle 术语中,Project 对象对应的是 Build Script

    • 加载插件其实是调用它的apply函数。

    • Project 包含若干 Tasks。另外,由于 Project 对应具体的工程,所以需要为 Project 加载所需要的插件,比如为 Java 工程加载 Java 插件。其实,一个 Project 包含多少 Task 往往是插件决定的

  • Task基础概念:

    • Task

    • 一个Task表示构建的单个原子工作,例如编译类或生成javadoc。

    • 每个Task都属于一个Project。

    • 一组有依赖关系的Task,组成了Project。

  • 查看gradle源码:通过Android Studio即可

444.png

MotionEvent处理:自行将原始的MotionEvent合并成为我们常用的事件序列。

  • 单击

  • 双击

  • 长按

  • 多指触控

  • Cancel事件的处理

项目

项目地址

tinyvampirepudge/hook-touch-event

效果:

  • 插件支持gradle4.2和gradle7.2

  • 插件支持常见的依赖方式。module、aar、jar等

gradle插件优势:

  • 对现有业务代码,基本上是无侵入式的修改。可以如果不需要,可以随时移除。

  • 增加字节码的相关耗时主要是在编译期间,非运行时。运行时只是增加正常的代码调用耗时。

  • 字节码增加代码之后,不会影响mapping文件中的行号。即不会影响现有代码的错误堆栈信息。

555.png

插件兼容性

666.png

项目架构图

777.png

插件代码

目标:修改字节码,将所有经过Activity的MotionEvent都给我们的TouchEventDispatcher发送一份。

整体目录:

888.png

找到目标class

  • TouchEventTransform:遍历并找到我们的目标class,然后修改

    • getInputTypes:TransformManager.CONTENT_CLASS

    • getScopes:[实测] TransformManager.PROJECT_ONLY 配合每个子module下都apply插件,则可以遍历所有module下的class。

    • transform:遍历class文件,找到我们的目标class。

    • 借助asm插件中的ClassVisitor查找到目标类

修改目标class

  • PluginUtils.genDispatchTouchEvent:class中没有目标方法,增加对应方法默认实现的字节码

  • 借助asm插件中的MethodVisitor,在目标方法中通过字节码的方式添加我们的代码

  • 将字节码翻译成我们对应的asm插件(gradle)的代码

    • 先写一个测试文件,里面写好我们的方法

    • 然后在IDE中,借助IDE的ASM插件,查看对应的字节码。如下图所示

ff99c3fa-eca6-42da-85ab-8d86da4408da.png
c2db6edc-e49f-467e-833a-6b6462bf818f.png
  • 通过ASM插件查看对应的ASM代码:
7821aadb-5279-42c8-ae11-37e36c0caf5a.png
  • 接着查看MethodVisitor的api,找到与字节码对应的数据。示例结果如下:
54bf134c-9131-4338-8cff-c596ff86bfd5.png

事件处理的sdk:

TouchEventDispatcher:事件分发的入口。事件接收、校验

  • 数据校验

  • 数据包装成自己的对象(自行定义)

  • 通过WeakReference解除对原有的ctx的强引用

TouchEventCollector:采集原始的事件序列。

  • 生成事件序列:

    • 以MotionEvent.ACTION_DOWN开始

    • 以MotionEvent.ACTION_UP、MotionEvent.ACTION_CANCEL、MotionEvent.ACTION_POINTER_UP结束

  • 多指触控数据剔除掉。具体看业务需求

TouchEventClassification:事件序列归类。

  • MotionEvent.ACTION_CANCEL结尾的事件序列丢弃

  • 对MotionEvent.ACTION_MOVE事件做采样处理

  • 归类为我们需要的:单击、双击、长按事件序列

TouchEventReporter:事件上报。具体如何上报到服务器,自行实现

如何查看日志:

开发或者构建过程中,在Run/Build下查看日志输出:

17f9d244-b391-4d20-ba92-c2f4fb2eb8e7.png
61360cc7-daaa-4c85-b44c-e8cb00e4a52e.png

项目运行起来后,在logcat中查看:

搜索TouchEventDispatcher、TouchEventCollector、TouchEventClassification、TouchEventReporter等关键字,即可查看对应的日志

b50227c4-5dda-49c6-abfa-09ea24c1e407.png

README:更多细节,请看README

https://github.com/tinyvampirepudge/hook-touch-event#readme

FAQ:

gradle版本从v4切换到v7后,修改了gradle版本和jdk版本之后,执行gradle命令发布仓库到本地,依旧报jdk version的错误。

  • 查看项目配置,我们jdk版本是11。
392a88e5-1759-4dde-ae1e-af300ec49de8.png
  • 执行的gradle命令

./gradlew clean touch-event-gradle-plugin-v7:publishToLocalRepoPublicationToMavenRepository
  • 报错信息

  • What went wrong: A problem occurred evaluating project ':aar-module'. > Failed to apply plugin 'com.android.internal.library'. > Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8. Your current JDK is located in /Library/Java/JavaVirtualMachines/jdk1.8.0_261.jdk/Contents/Home/jre You can try some of the following options: - changing the IDE settings. - changing the JAVA_HOME environment variable. - changing org.gradle.java.home in gradle.properties. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights.

从报错信息可以看出,在gradle命令行的环境下,jdk版本依旧不是期望的11。我们通过./gradlew -v来查看下:

(base) tinytongtong@tinytonongdembp hook-touch-event % ./gradlew -v  

------------------------------------------------------------
Gradle 7.3.3
------------------------------------------------------------

Build time:   2021-12-22 12:37:54 UTC
Revision:     6f556c80f945dc54b50e0be633da6c62dbe8dc71

Kotlin:       1.5.31
Groovy:       3.0.9
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          1.8.0_261 (Oracle Corporation 25.261-b12)
OS:           Mac OS X 10.16 x86_64

A:

  • 此时我们有两种解决方式,一种是想办法修改全局的jdk环境变量中的版本,另一种就比较简单,我们通过双击Gradle视图中对应Task的方式来执行任务(而不是./gradlew命令)。

  • 这里推荐双击Gradle视图中对应Task的方式来执行任务的方式。

2ec1fadb-8363-401b-aa8f-48c19cc450ed.png

Q: Could not find tools.jar. Please check that /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home contains a valid JDK installation.

c86d4ba9-1750-4b16-aef4-8e13d6e1fb0b.png

A: https://blog.csdn.net/gongsunjinqian/article/details/121228000

Q:

A:

参考:

一张图看懂Android编译流程

Build Workflow

transform + asm资料

Chapter 4. The class File Format

JVM指令集:Chapter 6. The Java Virtual Machine Instruction Set

一文读懂Android View事件分发机制

Android中点击事件的来源

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容