写在前面:

  • 在根底熟练的根底上,完全能够考虑根据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插件检查细节:
    • gradle插件分享-手把手教你写gradle插件
  • 检查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插件分享-手把手教你写gradle插件

  • 详细的图:

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

运用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插件
  • 适配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文件中的行号。即不会影响现有代码的过错堆栈信息。

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

插件兼容性

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

项目架构图

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

插件代码

方针:修正字节码,将一切经过Activity的MotionEvent都给咱们的TouchEventDispatcher发送一份。

全体目录:

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

  • 找到方针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插件,检查对应的字节码。如下图所示
      • gradle插件分享-手把手教你写gradle插件

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

  • 经过ASM插件检查对应的ASM代码:

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

  • 接着检查MethodVisitor的api,找到与字节码对应的数据。示例结果如下:

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

事情处理的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下检查日志输出:

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

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

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

查找TouchEventDispatcher、TouchEventCollector、TouchEventClassification、TouchEventReporter等关键字,即可检查对应的日志

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

README:更多细节,请看README

github.com/tinyvampire…

FAQ:

gradle版别从v4切换到v7后,修正了gradle版别和jdk版别之后,履行gradle指令发布仓库到本地,依旧报jdk version的过错。

  • 检查项目装备,咱们jdk版别是11。

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

  • 履行的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的办法来履行使命的办法。

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

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

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

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中点击事情的来历