###一衰琐、原理介紹
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)文件到輸出路徑
上圖展示的代碼中沒(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)搭建
????4恕出、打開(kāi)?build.gralde?文件询枚,替換全部?jī)?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
????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鳄乏。