概念
編譯插樁
就是在代碼編譯期間修改修改已有的代碼或者生成新的代碼佛呻。
編譯插樁技術(shù)從對代碼修改的時機上來說可以分為兩種:
Java 文件
:在編譯最開始的時候介入带猴,動態(tài)生成 Java 文件历极,之后編譯器將生成的 Java 文件編譯成 class 文件丢胚,像 ButterKnife绍哎、Dagger 都是通過 這種方式生成代碼的央碟。對應的技術(shù)主要是APT(Annotation Process Tools
字節(jié)碼文件
:在生成 class 文件后介入遍蟋,直接修改 class文件的字節(jié)碼吹害,達到修改代碼的目的。常用的字節(jié)碼編程框架有AspectJ
虚青、Javassist
它呀、ASM
等
什么是字節(jié)碼?
Java 字節(jié)碼是Java虛擬機執(zhí)行的一種指令格式棒厘。Java源文件經(jīng)Java編譯器后得到Java字節(jié)碼(.class)文件纵穿。Java字節(jié)碼(.class)文件可以看作是Java虛擬機的可執(zhí)行文件。這些字節(jié)碼(.class)文件擁有足夠的元數(shù)據(jù)來解析類中的所有元素:類名稱绊谭、方法政恍、屬性以及 Java 字節(jié)碼(指令)
如何查看字節(jié)碼
這里拿AndroidStudio舉例,所有基于IDEA的IDE應該都一樣达传。
在Settings -> Tools中添加External Tools篙耗,輸入Name和下面三要素,保存即可
$JDKPath$\bin\javap
-c -verbose $FileClass$
$OutputPath$
每次生成字節(jié)碼之前記得先
build/rebuild
一下工程宪赶,不然會失敗簡單分析下字節(jié)碼構(gòu)成
- kotlin文件查看方式
Android字節(jié)碼編程
在安卓中宗弯,編譯過程是由gradle task來執(zhí)行的,Gradle1.5以后提供了transform-api可以在代碼轉(zhuǎn)化為.class文件之后再打包成dex文件之前對它進行處理搂妻,所以我們可以自定義transform蒙保,在appcompileDebugJavaWithJavac這個gradle task之后就會走我們自定義的transform。
使用場景
-
代碼生成
欲主。除了 Dagger邓厕、ButterKnife 這些常用的注解生成框架,Protocol Buffers扁瓢、數(shù)據(jù)庫 ORM 框架也都會在編譯過程生成代碼详恼。代碼生成隔離了復雜的內(nèi)部實現(xiàn),讓開發(fā)更加簡單高效引几,而且也減少了手工重復的勞動量昧互,降低了出錯的可能性。 -
代碼監(jiān)控
。除了網(wǎng)絡監(jiān)控和耗電監(jiān)控敞掘,我們可以利用編譯插樁技術(shù)實現(xiàn)各種各樣的性能監(jiān)控叽掘。為什么不直接在源碼中實現(xiàn)監(jiān)控功能呢?首先我們不一定有第三方 SDK 的源碼玖雁,其次某些調(diào)用點可能會非常分散更扁,例如想監(jiān)控代碼中所有 new Thread() 調(diào)用,通過源碼的方式并不那么容易實現(xiàn)赫冬。 -
代碼修改
疯潭。我們在這個場景擁有無限的發(fā)揮空間,例如某些第三方 SDK 庫沒有源碼面殖,我們可以給它內(nèi)部的一個崩潰函數(shù)增加 try catch竖哩,或者說替換它的圖片庫等。我們也可以通過代碼修改實現(xiàn)無痕埋點脊僚。 -
代碼分析
相叁。上一期我講到持續(xù)集成,里面的自定義代碼檢查就可以使用編譯插樁技術(shù)實現(xiàn)辽幌。例如檢查代碼中的 new Thread() 調(diào)用增淹、檢查代碼中的一些敏感權(quán)限使用等。事實上乌企,F(xiàn)indbugs 這些第三方的代碼檢查工具也同樣使用的是編譯插樁技術(shù)實現(xiàn)虑润。