gradle插件分享-手把手教你寫(xiě)gradle插件

寫(xiě)在前面:

  • 在基礎(chǔ)熟練的基礎(chǔ)上,完全可以考慮基于Booster、ByteX等框架來(lái)開(kāi)發(fā)各薇,效率應(yīng)該會(huì)高一些顽照。

  • 修改字節(jié)碼的插件不止asm一個(gè)乏冀,還有javaassist等吉嚣,可以多做一些嘗試幔亥,按照需求選擇適合自己項(xiàng)目的琳疏。

  • 本次分享的目的旨在展示gradle插件開(kāi)發(fā)的過(guò)程粪般、思路拼余、需要的基礎(chǔ)、遇到問(wèn)題后如何分析等亩歹,核心在于打好基礎(chǔ)匙监。

整體目標(biāo):hook應(yīng)用內(nèi)所有的手勢(shì),還原成操作手勢(shì)事件小作,交由服務(wù)端進(jìn)行軌跡還原等操作亭姥。

核心任務(wù)拆分

核心任務(wù)聚焦:拿到應(yīng)用內(nèi)所有手勢(shì)事件的MotionEvent

關(guān)鍵節(jié)點(diǎn):

事件分發(fā)-何處hook
字節(jié)碼基礎(chǔ)-如何修改
apk構(gòu)建過(guò)程-何時(shí)修改
使用gradle-如何開(kāi)發(fā)插件
MotionEvent處理:自行將原始的MotionEvent合并成為我們常用的事件序列。

事件分發(fā)-何處hook

hook點(diǎn):activity的時(shí)機(jī)比較合適

  • 觸摸事件最終都會(huì)交由Acivity來(lái)處理

  • Acivity#dispatchTouchEvent方法負(fù)責(zé)分發(fā)給對(duì)應(yīng)的view進(jìn)行處理

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

最終做到的如下所示:


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

適配不同版本的Activity

  • 對(duì)特定的根Activity做處理顾稀,這樣可以對(duì)其子類(lèi)進(jìn)行處理致份,可以覆蓋所有的Activity。

  • AppCompatActivity:

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

字節(jié)碼基礎(chǔ)-如何修改

  • 字節(jié)碼本質(zhì):二進(jìn)制文件

    • jvm校驗(yàn)通過(guò)的就是合法的字節(jié)碼文件础拨,不問(wèn)來(lái)源氮块。

    • 比如你通過(guò)文本編輯器寫(xiě)的字節(jié)碼文件,只要符合字節(jié)碼格式诡宗,那也是合法的字節(jié)碼文件滔蝉。

  • 字節(jié)碼格式:

111.png
  • 查看Java字節(jié)碼內(nèi)容的幾種方式

  • jvm指令集

  • 如何修改字節(jié)碼- 借助ASM等工具.

    • ASM官網(wǎng)

    • 1、ClassReader:對(duì)class文件進(jìn)行讀取與解析塔沃;

    • 2蝠引、ClassWriter:參與字節(jié)碼修改,并將修改后的字節(jié)碼內(nèi)容以字節(jié)流的形式返回蛀柴。

    • 3螃概、使用ClassNode與MethodNode配合判斷:目標(biāo)Class中如果沒(méi)有目標(biāo)方法,就使用ClassWriter + MethodVisitor鸽疾,無(wú)中生有的增加目標(biāo)方法(dispatchTouchEvent)的默認(rèn)實(shí)現(xiàn)吊洼。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }
    
    • 2、ClassVisitor和MethodVisitor:找到目標(biāo)Class(CompatActivity的子類(lèi))制肮,如果存在目標(biāo)方法(dispatchTouchEvent)冒窍,則直接在方法入口處增加我們的工具方法調(diào)用。
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        TouchEventDispatcher.dispatchTouchEvent(MainActivity.this, ev);
        return super.dispatchTouchEvent(ev);
    }
    
    • class會(huì)遍歷兩遍豺鼻。

apk構(gòu)建過(guò)程-何時(shí)修改

  • 整體架構(gòu)圖
  • 詳細(xì)的圖:


    333.png

使用gradle-如何開(kāi)發(fā)插件

  • 使用groovy語(yǔ)言開(kāi)發(fā)综液,面向Java平臺(tái)。也可以kotlin開(kāi)發(fā)(趨勢(shì))儒飒。

  • Project基礎(chǔ)概念

    • Project

    • 每一個(gè) build.gradle 文件都會(huì)轉(zhuǎn)換成一個(gè) Project 對(duì)象谬莹。在 Gradle 術(shù)語(yǔ)中,Project 對(duì)象對(duì)應(yīng)的是 Build Script

    • 加載插件其實(shí)是調(diào)用它的apply函數(shù)附帽。

    • Project 包含若干 Tasks埠戳。另外,由于 Project 對(duì)應(yīng)具體的工程士葫,所以需要為 Project 加載所需要的插件乞而,比如為 Java 工程加載 Java 插件送悔。其實(shí)慢显,一個(gè) Project 包含多少 Task 往往是插件決定的

  • Task基礎(chǔ)概念:

    • Task

    • 一個(gè)Task表示構(gòu)建的單個(gè)原子工作欠啤,例如編譯類(lèi)或生成javadoc荚藻。

    • 每個(gè)Task都屬于一個(gè)Project。

    • 一組有依賴(lài)關(guān)系的Task洁段,組成了Project应狱。

  • 查看gradle源碼:通過(guò)Android Studio即可

444.png

MotionEvent處理:自行將原始的MotionEvent合并成為我們常用的事件序列岸蜗。

  • 單擊

  • 雙擊

  • 長(zhǎng)按

  • 多指觸控

  • Cancel事件的處理

項(xiàng)目

項(xiàng)目地址

tinyvampirepudge/hook-touch-event

效果:

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

  • 插件支持常見(jiàn)的依賴(lài)方式。module叠蝇、aar璃岳、jar等

gradle插件優(yōu)勢(shì):

  • 對(duì)現(xiàn)有業(yè)務(wù)代碼,基本上是無(wú)侵入式的修改悔捶×蹇叮可以如果不需要,可以隨時(shí)移除蜕该。

  • 增加字節(jié)碼的相關(guān)耗時(shí)主要是在編譯期間犁柜,非運(yùn)行時(shí)。運(yùn)行時(shí)只是增加正常的代碼調(diào)用耗時(shí)堂淡。

  • 字節(jié)碼增加代碼之后赁温,不會(huì)影響mapping文件中的行號(hào)。即不會(huì)影響現(xiàn)有代碼的錯(cuò)誤堆棧信息淤齐。

555.png

插件兼容性

666.png

項(xiàng)目架構(gòu)圖

777.png

插件代碼

目標(biāo):修改字節(jié)碼股囊,將所有經(jīng)過(guò)Activity的MotionEvent都給我們的TouchEventDispatcher發(fā)送一份。

整體目錄:

888.png

找到目標(biāo)class

  • TouchEventTransform:遍歷并找到我們的目標(biāo)class更啄,然后修改

    • getInputTypes:TransformManager.CONTENT_CLASS

    • getScopes:[實(shí)測(cè)] TransformManager.PROJECT_ONLY 配合每個(gè)子module下都apply插件稚疹,則可以遍歷所有module下的class。

    • transform:遍歷class文件,找到我們的目標(biāo)class内狗。

    • 借助asm插件中的ClassVisitor查找到目標(biāo)類(lèi)

修改目標(biāo)class

  • PluginUtils.genDispatchTouchEvent:class中沒(méi)有目標(biāo)方法怪嫌,增加對(duì)應(yīng)方法默認(rèn)實(shí)現(xiàn)的字節(jié)碼

  • 借助asm插件中的MethodVisitor,在目標(biāo)方法中通過(guò)字節(jié)碼的方式添加我們的代碼

  • 將字節(jié)碼翻譯成我們對(duì)應(yīng)的asm插件(gradle)的代碼

    • 先寫(xiě)一個(gè)測(cè)試文件柳沙,里面寫(xiě)好我們的方法

    • 然后在IDE中岩灭,借助IDE的ASM插件,查看對(duì)應(yīng)的字節(jié)碼赂鲤。如下圖所示

ff99c3fa-eca6-42da-85ab-8d86da4408da.png
c2db6edc-e49f-467e-833a-6b6462bf818f.png
  • 通過(guò)ASM插件查看對(duì)應(yīng)的ASM代碼:
7821aadb-5279-42c8-ae11-37e36c0caf5a.png
  • 接著查看MethodVisitor的api噪径,找到與字節(jié)碼對(duì)應(yīng)的數(shù)據(jù)。示例結(jié)果如下:
54bf134c-9131-4338-8cff-c596ff86bfd5.png

事件處理的sdk:

TouchEventDispatcher:事件分發(fā)的入口数初。事件接收找爱、校驗(yàn)

  • 數(shù)據(jù)校驗(yàn)

  • 數(shù)據(jù)包裝成自己的對(duì)象(自行定義)

  • 通過(guò)WeakReference解除對(duì)原有的ctx的強(qiáng)引用

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

  • 生成事件序列:

    • 以MotionEvent.ACTION_DOWN開(kāi)始

    • 以MotionEvent.ACTION_UP泡孩、MotionEvent.ACTION_CANCEL车摄、MotionEvent.ACTION_POINTER_UP結(jié)束

  • 多指觸控?cái)?shù)據(jù)剔除掉。具體看業(yè)務(wù)需求

TouchEventClassification:事件序列歸類(lèi)仑鸥。

  • MotionEvent.ACTION_CANCEL結(jié)尾的事件序列丟棄

  • 對(duì)MotionEvent.ACTION_MOVE事件做采樣處理

  • 歸類(lèi)為我們需要的:?jiǎn)螕羲辈ァ㈦p擊、長(zhǎng)按事件序列

TouchEventReporter:事件上報(bào)眼俊。具體如何上報(bào)到服務(wù)器意狠,自行實(shí)現(xiàn)

如何查看日志:

開(kāi)發(fā)或者構(gòu)建過(guò)程中,在Run/Build下查看日志輸出:

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

項(xiàng)目運(yùn)行起來(lái)后泵琳,在logcat中查看:

搜索TouchEventDispatcher摄职、TouchEventCollector、TouchEventClassification获列、TouchEventReporter等關(guān)鍵字谷市,即可查看對(duì)應(yīng)的日志

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

README:更多細(xì)節(jié),請(qǐng)看README

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

FAQ:

gradle版本從v4切換到v7后击孩,修改了gradle版本和jdk版本之后迫悠,執(zhí)行g(shù)radle命令發(fā)布倉(cāng)庫(kù)到本地,依舊報(bào)jdk version的錯(cuò)誤巩梢。

  • 查看項(xiàng)目配置创泄,我們jdk版本是11。
392a88e5-1759-4dde-ae1e-af300ec49de8.png
  • 執(zhí)行的gradle命令

./gradlew clean touch-event-gradle-plugin-v7:publishToLocalRepoPublicationToMavenRepository
  • 報(bào)錯(cuò)信息

  • 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.

從報(bào)錯(cuò)信息可以看出括蝠,在gradle命令行的環(huán)境下鞠抑,jdk版本依舊不是期望的11。我們通過(guò)./gradlew -v來(lái)查看下:

(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:

  • 此時(shí)我們有兩種解決方式忌警,一種是想辦法修改全局的jdk環(huán)境變量中的版本搁拙,另一種就比較簡(jiǎn)單,我們通過(guò)雙擊Gradle視圖中對(duì)應(yīng)Task的方式來(lái)執(zhí)行任務(wù)(而不是./gradlew命令)。

  • 這里推薦雙擊Gradle視圖中對(duì)應(yīng)Task的方式來(lái)執(zhí)行任務(wù)的方式箕速。

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事件分發(fā)機(jī)制

Android中點(diǎn)擊事件的來(lái)源

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酪碘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盐茎,更是在濱河造成了極大的恐慌兴垦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件字柠,死亡現(xiàn)場(chǎng)離奇詭異探越,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)募谎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)扶关,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阴汇,“玉大人数冬,你說(shuō)我怎么就攤上這事〔笫” “怎么了拐纱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)哥倔。 經(jīng)常有香客問(wèn)我秸架,道長(zhǎng),這世上最難降的妖魔是什么咆蒿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任东抹,我火速辦了婚禮,結(jié)果婚禮上沃测,老公的妹妹穿的比我還像新娘缭黔。我一直安慰自己,他們只是感情好蒂破,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布馏谨。 她就那樣靜靜地躺著,像睡著了一般附迷。 火紅的嫁衣襯著肌膚如雪惧互。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天喇伯,我揣著相機(jī)與錄音喊儡,去河邊找鬼。 笑死稻据,一個(gè)胖子當(dāng)著我的面吹牛艾猜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼箩朴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岗喉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起炸庞,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钱床,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后埠居,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體查牌,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年滥壕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纸颜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绎橘,死狀恐怖胁孙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情称鳞,我是刑警寧澤涮较,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站冈止,受9級(jí)特大地震影響狂票,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熙暴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一闺属、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧周霉,春花似錦掂器、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至匠楚,卻和暖如春巍膘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芋簿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工峡懈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人与斤。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓肪康,卻偏偏與公主長(zhǎng)得像荚恶,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子磷支,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容