写在前面:
- 在根底熟练的根底上,完全能够考虑根据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校验经过的就是合法的字节码文件,不问来历。
- 比方你经过文本编辑器写的字节码文件,只要契合字节码格局,那也是合法的字节码文件。
-
字节码格局:
- Chapter 4. The
class
File Format - [扩展]IDE凭借jclasslib插件检查细节:
- Chapter 4. The
-
检查Java字节码内容的几种办法
-
jvm指令集
- 请看[JVM指令集:Chapter 6. The Java Virtual Machine Instruction Set](docs.oracle.com/javase/spec…)
-
怎么修正字节码- 凭借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构建进程-何时修正
- 全体架构图
- 详细的图:
运用gradle-怎么开发插件
-
运用groovy语言开发,面向Java平台。也能够kotlin开发(趋势)。
- groovy官网
- groovy api 网址
- The Groovy Development Kit
-
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即可
-
适配gradle版别。这儿挑选支撑有代表性的gradle 4.2和 gradle 7.2。
- [Gradle插件版别和Gradle sdk版别的对应联系](developer.android.com/studio/rele…)
-
gradle相关材料:
-
Gradle API 文档。点击
INDEX
,然后查找脚本名字即可。 -
Developing Custom Gradle Plugins
-
transform + asm材料
-
Android Gradle权威指南.pdf
-
Android之Gradle 深化理解.pdf
-
MotionEvent处理:自行将原始的MotionEvent兼并成为咱们常用的事情序列。
-
单击
-
双击
-
长按
-
多指触控
-
Cancel事情的处理
项目
项目地址
[tinyvampirepudge/hook-touch-event](github.com/tinyvampire…)
作用:
- 插件支撑gradle4.2和gradle7.2
- 插件支撑常见的依赖办法。module、aar、jar等
gradle插件优势:
- 对现有业务代码,基本上是无侵入式的修正。能够假如不需求,能够随时移除。
- 添加字节码的相关耗时主要是在编译期间,非运行时。运行时仅仅添加正常的代码调用耗时。
- 字节码添加代码之后,不会影响mapping文件中的行号。即不会影响现有代码的过错堆栈信息。
插件兼容性
项目架构图
插件代码
方针:修正字节码,将一切经过Activity的MotionEvent都给咱们的TouchEventDispatcher发送一份。
全体目录:
-
找到方针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插件,检查对应的字节码。如下图所示
-
- 经过ASM插件检查对应的ASM代码:
- 接着检查MethodVisitor的api,找到与字节码对应的数据。示例结果如下:
事情处理的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下检查日志输出:
项目运行起来后,在logcat中检查:
查找TouchEventDispatcher、TouchEventCollector、TouchEventClassification、TouchEventReporter等关键字,即可检查对应的日志
README:更多细节,请看README
github.com/tinyvampire…
FAQ:
gradle版别从v4切换到v7后,修正了gradle版别和jdk版别之后,履行gradle指令发布仓库到本地,依旧报jdk version的过错。
- 检查项目装备,咱们jdk版别是11。
- 履行的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
ingradle.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的办法来履行使命的办法。
Q: Could not find tools.jar. Please check that /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home contains a valid JDK installation.
A: blog.csdn.net/gongsunjinq…
参阅:
一张图看懂Android编译流程
Build Workflow
transform + asm材料
Chapter 4. The class
File Format
[JVM指令集:Chapter 6. The Java Virtual Machine Instruction Set](docs.oracle.com/javase/spec…)
一文读懂Android View事情分发机制
Android中点击事情的来历