Android通過(guò)javassist修改類

###一衰琐、原理介紹

1、App構(gòu)建是將代碼編譯為.class文件炼蹦,然后打包成dex文件之后輸出apk

2羡宙、Gradle構(gòu)建App由一個(gè)個(gè)Task組成,每個(gè)Task作用實(shí)際上是接收一個(gè)輸入(編譯App所需的資源)然后進(jìn)行處理然后有一個(gè)輸出

3掐隐、Gradle1.5以后提供了transform-api可以在代碼轉(zhuǎn)化為.class文件之后再打包成dex文件之前對(duì)它進(jìn)行處理

4狗热、Javassist可以處理.class文件

所以我們可以通過(guò)自定義gradle插件的方式利用javassist在打包的過(guò)程中修改.class文件钞馁,這樣編譯出來(lái)的apk文件中就會(huì)是我們修改過(guò)的class

###二、Transfrom-API介紹

getName:用于指明本Transform的名字匿刮,這個(gè) name 并不是最終的名字僧凰,在TransformManager 中會(huì)對(duì)名字再處理

getInputTypes:用于指明Transform的輸入類型,可以作為輸入過(guò)濾的手段

????–CLASSES表示要處理編譯后的字節(jié)碼熟丸,可能是 jar 包也可能是目錄

?????–RESOURCES表示處理標(biāo)準(zhǔn)的 java 資源

getScopes:用于指明Transform的作用域

????–PROJECT? ?????????????????????? 只處理當(dāng)前項(xiàng)目

????–SUB_PROJECTS? 只處理子項(xiàng)目

????–PROJECT_LOCAL_DEPS? 只處理當(dāng)前項(xiàng)目的本地依賴,例如jar, aar

????–EXTERNAL_LIBRARIES? 只處理外部的依賴庫(kù)

????–PROVIDED_ONLY? 只處理本地或遠(yuǎn)程以provided形式引入的依賴庫(kù)

????–TESTED_CODE? ?????????????????????? 只處理測(cè)試代碼

isIncremental:用于指明是否是增量構(gòu)建训措。

transform:核心方法,用于自定義處理,在這個(gè)方法中我們可以拿到要處理的.class文件路徑光羞、jar包路徑绩鸣、輸出文件路徑等,拿到文件之后就可以對(duì)他們進(jìn)行操作

利用Transform-api處理.class文件有個(gè)標(biāo)準(zhǔn)流程纱兑,拿到輸入路徑->取出要處理的文件->處理文件->移動(dòng)文件到輸出路徑


Transform-api處理流程

上圖展示的代碼中沒(méi)有包含處理過(guò)程呀闻,我們只需要在FileUtils.copy函數(shù)之前對(duì)拿到的文件進(jìn)行處理即可

###三、javassist介紹

? ??介紹:Javassist是一個(gè)動(dòng)態(tài)類庫(kù)萍启,可以用來(lái)檢查总珠、”動(dòng)態(tài)”修改以及創(chuàng)建 Java類。其功能與jdk自帶的反射功能類似勘纯,但比反射功能更強(qiáng)大局服。

? ? 常用類

? ??ClassPool:javassist的類池,使用ClassPool類可以跟蹤和控制所操作的類,它的工作方式與 JVM類裝載器非常相似驳遵,

????CtClass: CtClass提供了檢查類數(shù)據(jù)(如字段和方法)以及在類中添加新字段淫奔、方法和構(gòu)造函數(shù)、以及改變類堤结、父類和接口的方法唆迁。不

? ??????過(guò),????Javassist 并未提供刪除類中字段竞穷、方法或者構(gòu)造函數(shù)的任何方法唐责。

????CtField:用來(lái)訪問(wèn)域

????CtMethod :用來(lái)訪問(wèn)方法?

? ?CtConstructor:用來(lái)訪問(wèn)構(gòu)造器

? ??基本用法

? ? ? ? ?1、添加類搜索路徑

????????? ClassPool pool =ClassPool.getDefault();

????????? ?pool.insertClassPath("/usr/local/javalib");

????????2瘾带、添加方法

? ? ? ? ?CtClass point =ClassPool.getDefault().get("Point");

? ? ? ? ?CtMethod m =CtNewMethod.make( "public int xmove(int dx) { x += dx; }", point);point.addMethod(m);

????????3鼠哥、修改方法

? ? ? ? ?CtClass point =ClassPool.getDefault().get("Point");?

? ? ? ? ?CtMethod m= point.getDeclaredMethod(“show", null)

? ? ? ? ?m.insertAfter(“System.out.prinln(“x:” + x + “,y:) + y”))

????????4、添加字段

?????? ? CtClass point =ClassPool.getDefault().get("Point");

????????? CtField f = newCtField(CtClass.intType, "z", point);

? ????????point.addField(f);

###四看政、自定義Gradle插件

? ? 自定義插件可以直接新建一個(gè)名為buildSrc的module不過(guò)這樣的插件只能自己工程用朴恳,還有另外一種方式可以發(fā)布到j(luò)center提供別別人用也可以發(fā)布到本地自己使用。這里是第二種方式的步驟:這里是原文

? ??1允蚣、新建一個(gè) Module于颖,此Module 用于開(kāi)發(fā)插件,類型選什么都無(wú)所謂嚷兔,后面會(huì)大改森渐。

????2做入、在 Project 目錄視圖模式下,清空build.gradle 文件的內(nèi)容章母,刪除其余的所有文件母蛛。

????3翩剪、然后在 module 中新建多個(gè)文件夾?src/main/groovy?乳怎,再新建包名文件夾。 在 main 目錄下再新建resources?目錄前弯,在resources?目錄下再新

? ??建?META-INF?文件夾蚪缀,再新建文件夾gradle-plugins,這樣就完成了 gradle插件的目錄結(jié)構(gòu)搭建


Module文件結(jié)構(gòu)

????4恕出、打開(kāi)?build.gralde?文件询枚,替換全部?jī)?nèi)容


Build.gradle內(nèi)容

????5、編寫(xiě)插件內(nèi)容浙巫。在剛剛新建的包名下 再次新建一個(gè)文件?MyPlugin.groovy?金蜀,注意文件類型,一定是?groovy?類型文件

????6的畴、在resources/META-INF/gradle-plugins?目錄下新建一個(gè)?.properties?文件渊抄,注意該文件的命名就是你使用此插件時(shí)的名稱,這里命名

? ??為?com.app.myplugin.properties?丧裁,一定要注意后綴名稱护桦,那么使用時(shí)的名稱就是com.app.myplugin,文件里面的內(nèi)容填寫(xiě)如下: ????implementation-class=com.app.plugin.MyPlugin煎娇,這里是?key = value?的形式二庵,值就是剛剛自定義的 插件( groovy 文件 )的全名,也就是徑加上類名稱缓呛。

????7催享、發(fā)布插件到本地,修改build.gradle文件哟绊,這個(gè)時(shí)候右側(cè)的 gradle Toolbar 就會(huì)在module下多出一個(gè)task :upload-uploadArchives因妙。?clean工程然后運(yùn)行upload-uploadArchives


發(fā)布插件

????8、引用插件


引用插件

? ? ? a匿情、修改工程根目錄下的build.gradle

? ? ? ?b兰迫、在module的目錄下的build.gradle中添加

????? apply plugin:'com.app.plugin.myplugin' //這里就填寫(xiě).properties 文件的名稱

###五、實(shí)操

? ? 我們可以按照上面的步驟進(jìn)行一次demo編寫(xiě)炬称,這里要做的功能是在代碼中所有的View.OnClickListener類的onClick方法中插入一個(gè)Toast汁果,在每次編譯之后我們可以到文件夾D:\as_workspace\sample\javassist\app\build\intermediates\transforms\ModifyTransform\debug下查看.class文件是否修改成功,D:\as_workspace\sample\javassist\這個(gè)是代碼工程目錄ModifyTransform是自定義Gradle插件的名稱玲躯。修改class文件在實(shí)際中還是挺有用處的据德,比如我們可以用來(lái)做無(wú)埋點(diǎn)或者修改第三方j(luò)ar包中的bug鳄乏。

代碼:https://github.com/yaozhukuang/javassist

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市棘利,隨后出現(xiàn)的幾起案子橱野,更是在濱河造成了極大的恐慌,老刑警劉巖善玫,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件水援,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茅郎,警方通過(guò)查閱死者的電腦和手機(jī)蜗元,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)系冗,“玉大人奕扣,你說(shuō)我怎么就攤上這事≌凭矗” “怎么了惯豆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奔害。 經(jīng)常有香客問(wèn)我楷兽,道長(zhǎng),這世上最難降的妖魔是什么舀武? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任拄养,我火速辦了婚禮,結(jié)果婚禮上银舱,老公的妹妹穿的比我還像新娘瘪匿。我一直安慰自己,他們只是感情好寻馏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布棋弥。 她就那樣靜靜地躺著,像睡著了一般诚欠。 火紅的嫁衣襯著肌膚如雪顽染。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天轰绵,我揣著相機(jī)與錄音粉寞,去河邊找鬼。 笑死左腔,一個(gè)胖子當(dāng)著我的面吹牛唧垦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播液样,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼振亮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巧还!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起坊秸,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤麸祷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后褒搔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體阶牍,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年站超,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荸恕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡死相,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咬像,到底是詐尸還是另有隱情算撮,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布县昂,位于F島的核電站肮柜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏倒彰。R本人自食惡果不足惜审洞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望待讳。 院中可真熱鬧芒澜,春花似錦、人聲如沸创淡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琳彩。三九已至誊酌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間露乏,已是汗流浹背碧浊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘟仿,地道東北人箱锐。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像猾骡,于是被迫代替她去往敵國(guó)和親瑞躺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敷搪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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