天天看點

android asm gradle,Android Gradle Plugin的應用

背景:

1.趨勢:目前很多知名架構在後期維護中基于性能優化,代碼解耦的考慮都加入Gradle Plugin的技術,如Alibaba的ARouter, 360的Replugin等等。在後期的版本更新後,在性能上都有很大的優化。

2.需求:随着項目中對于APM(Application Performance Management) 越來越關注,後期功能上會加入性能監控,網絡請求耗時等一些監控,這個時候為了減少對原業務功能的影響,​達到“無需修改原有結構,無侵入接入”和“無性能損害”的目标,就需要有一種辦法在編譯階段自動插入代碼實作(運作階段操作肯定會消耗性能,pass)。那就是傳說中的“插樁”,AOP思想(面向切面程式設計),使用Gradle Plugin 技術。

3.現狀:産品經理為了對産品上線之後使用者操作資料的統計,每次上線前會對代碼中增加埋點。随着功能的龐大和業務的複雜,造成埋點代碼越來越多,這些代碼在某種程度會影響業務邏輯的閱讀。這個時候如果能把埋點代碼和業務代碼進行分離,隻要在編譯的時候把埋點代碼注入到業務代碼就可以了。

概述

Gradle Plugin是Android項目中為了達到優化性能,代碼解耦的目标,在編譯階段通過位元組碼的改變在已存在的類中插入代碼,或者建立一個新的類,采用的是AOP面向切面思想程式設計,接下來以下幾個方面進行講述:

1.Android App的編譯過程

2.自定義Gradle Plugin的建立和Transform api的使用

3.使用asm實作位元組碼插樁

編譯過程

android asm gradle,Android Gradle Plugin的應用

編譯過程

上圖介紹了一個app是如何編譯成在手機上運作的apk,gradle plugin 是在生成.class檔案之後,生成.dex之前對位元組碼進行操作。它其中包含.class 檔案和第三方的jar檔案,在編譯過程中周遊拿到這些檔案,然後對需要更改的類檔案進行更改。

自定義Gradle-Plugin 插件

1.自定義插件

1.首先引入jar包:

2.0.0以前:compile'com.android.tools.build:transform-api:1.5.0'

2.0.0以後://從2.0.0版本開始就是在gradle-api中

implementation'com.android.tools.build:gradle-api:3.1.4

2.建立自定義插件:

首先建立自定義插件,在自定以插件中注冊一個自定義的transform,編寫語言可以是groovy,java,kotlin

android asm gradle,Android Gradle Plugin的應用

Arouter 建立的自定義插件

如上圖apply方法中隻有在主app中才會需要導入這個插件生成注冊的代碼。然後建立自定義RegisterTransform 注冊到插件中,其中建立了一個集合,指派給這個插件,這個會在後面講解。

2自定義transform

1.transform原理及應用

android asm gradle,Android Gradle Plugin的應用

transform原理

1.每一個transform 是一個Gradle task,TaskMandger 會把Transform 串聯起來,第一個 Transform 會把javac編譯的class檔案,jar包,resource(asset中的資源)接收到,然後進行處理,傳送給下一個Transform。

2.自定義的transform會插到系統自帶的前面。

3.dexBuilder,dexMerger,mergeJavaRes,mergeJniLibs,proguard 這些常見Transform都屬于系統的Transform。

2.transform類詳解

android asm gradle,Android Gradle Plugin的應用

自定義Transform

1.getName:傳回插件的名字,這個 name 并不是最終的名字,

格式如:transformClassesWith“name”ForDebug

2.getInputTypes: 擷取過濾的類型:

CONTENT_CLASS:表示要處理編譯後的位元組碼,可能是 jar 包也可能是目錄

CONTENT_RESOURCES:表示處理标準的 java 資源,在assert檔案夾中

3.getScopes:擷取過濾的範圍

PROJECT: 隻處理目前項目

SUB_PROJECTS:隻處理子項目

PROJECT_LOCAL_DEPS:隻處理目前項目的本地依賴,例如jar, aar

EXTERNAL_LIBRARIES:隻處理外部的依賴庫

PROVIDED_ONLY:隻處理本地或遠端以provided形式引入的依賴庫

TESTED_CODE:測試代碼

4 isIncremental: 目前 Transform 是否支援增量編譯

NOTCHANGED: 目前檔案不需處理,甚至複制操作都不用;

ADDED、CHANGED: 正常處理,輸出給下一個任務;

REMOVED: 移除outputProvider擷取路徑對應的檔案。

5:transform()方法的參數詳解

inputs :消費型輸入

referencedInputs:引用型輸入,無需輸出

isIncremental:是否增量更新

outputProvider:管理輸出路徑

6. transform 的優化:private  WaitableExecutor waitableExecutor;

waitableExecutor =WaitableExecutor.useGlobalSharedThreadPool();

//異步并發處理jar/class

waitableExecutor.execute(()->{

bytecodeWeaver.weaveJar(srcJar,destJar);returnnull;

});

//異步并發處理jar/class

waitableExecutor.execute(()->{

bytecodeWeaver.weaveSingleClassToFile(file,outputFile,inputDirPath);returnnull;

});

//等待所有任務結束

waitableExecutor.waitForTasksWithQuickFail(true);

3.ASM使用

簡介:

ASM 可以直接産生二進制的class 檔案,也可以在增強既有類的功能。Java class 被存儲在嚴格格式定義的 .class檔案裡,這些類檔案擁有足夠的中繼資料來解析類中的所有元素:類名稱、方法、屬性以及 Java 位元組碼(指令)。

ASM架構中的核心類有以下幾個:

ClassReader:該類用來解析編譯過的class位元組碼檔案。

ClassWriter:該類用來重新建構編譯後的類,比如說修改類名、屬性以及方法,甚至可以生成新的類的位元組碼檔案。

ClassVisitor:主要負責 “拜訪” 類成員資訊。其中包括标記在類上的注解,類的構造方法,類的字段,類的方法,靜态代碼塊。

AdviceAdapter:實作了MethodVisitor接口,主要負責 “拜訪” 方法的資訊,用來進行具體的方法位元組碼操作。

android asm gradle,Android Gradle Plugin的應用

ClassVisitor 實作

android asm gradle,Android Gradle Plugin的應用

MethodVisitor 實作

總結:Android Gradle Plugin 大概講到這,最後一步Asm實作可以使用Android studio 插件asm-bytecode-outline,它會生成asm實作代碼。