??最近在學(xué)習(xí)字節(jié)碼插樁技術(shù),利用字節(jié)碼插樁技術(shù),我們可以在編譯時(shí)期對(duì)字節(jié)碼進(jìn)行修改,達(dá)到完成一些特殊需求拙徽,比如埋點(diǎn)(可以聲明一個(gè)BaseActivity,在onCreate和onDestory中進(jìn)行埋點(diǎn))诗宣;統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間膘怕;熱修復(fù),ButterKnief召庞、Dagger等也用到了字節(jié)碼插樁技術(shù)岛心。
??在Android中要使用字節(jié)碼插樁技術(shù)需要完成三步:
- 自定義Gradle插件 :自定義插件来破,重寫(xiě)apply方法,注冊(cè)自定義Transform
- Transform Api使用:自定義Ttransform忘古,在transform方法中實(shí)現(xiàn)處理邏輯
-
Asm的使用: 在transform中使用Asm插入字節(jié)碼
??本文是實(shí)現(xiàn)第一步徘禁,自定義Gradle。
??實(shí)現(xiàn)自定義Gradle插件主要有三種方式:
1.在build.gradle中定義髓堪,直接在module的build.gradle中實(shí)現(xiàn)送朱,缺點(diǎn):只能在本項(xiàng)目中使用,不好復(fù)用旦袋。
2.buildSrc中使用骤菠。這種方式需要在項(xiàng)目中新建一個(gè)model命名為buildSrc,這個(gè)目錄就用來(lái)存放自定義插件疤孕,缺點(diǎn):只能在本項(xiàng)目中使用,不好復(fù)用央拖。
3.獨(dú)立Module中使用祭阀。這種方式就是完全獨(dú)立開(kāi)發(fā)一個(gè)Module,并且可以上傳至maven庫(kù)鲜戒,可以隨便用专控。
由于三種方式實(shí)現(xiàn)都差不多,前兩種局限性比較大遏餐,所以本文只對(duì)第三種進(jìn)行記錄伦腐。
1、新建Android Module選擇Android Library類(lèi)型即可
??除去src/main和build.gradle其余文件都刪除失都,并清除build.gradle內(nèi)容柏蘑,將以下內(nèi)容填入build.gradle,并同步gradle
apply plugin: 'groovy'
dependencies {
//gradle sdk
implementation gradleApi()
//groovy sdk
implementation localGroovy()
}
2粹庞、新建groovy文件咳焚,實(shí)現(xiàn)插件邏輯
??在src/main目錄下新建groovy目錄,在groovy目錄下新建com.example.clean目錄(名字自取即可),在該目錄下新建CleanPlugin.groovy文件庞溜,文件有一個(gè)綠色的G標(biāo)記革半,表示系統(tǒng)識(shí)別為groovy文件,可以導(dǎo)入gradle api流码。如果沒(méi)有出現(xiàn)綠色標(biāo)志又官,可以將文件名改為小寫(xiě)試試。
??這個(gè)cleanplugin.groovy就是我們要實(shí)現(xiàn)插件的主要邏輯漫试,我們需要聲明一個(gè)類(lèi)來(lái)實(shí)現(xiàn)Plugin<Project>接口六敬,在apply中實(shí)現(xiàn)主要邏輯。
package com.example.clean
import org.gradle.api.Plugin
import org.gradle.api.Project;
class cleanplugin implements Plugin<Project> {
@Override
void apply(Project project) {
println("clean plugin")
}
}
??注意記得導(dǎo)入包目錄商虐,否則會(huì)導(dǎo)致找不到插件實(shí)現(xiàn)類(lèi)
3觉阅、聲明插件
??在src/main目錄下新建resource目錄崖疤,接著新建META-INF目錄,繼續(xù)新建gradle-plugins目錄典勇,再新建com.example.firstplugin.properties文件(名字自取)劫哼,注意文件名即為到時(shí)候其他項(xiàng)目中引用的插件名,在該文件中寫(xiě)入如下內(nèi)容
//插件實(shí)現(xiàn)類(lèi)
implementation-class=com.example.clean.cleanplugin
4割笙、將插件上傳至maven庫(kù)
??在插件的build.gradle文件中添加插件groupid权烧、version等參數(shù)和上傳maven地址
apply plugin: 'maven-publish'
publishing {
publications {
mavenJava(MavenPublication) {
//其他項(xiàng)目使用插件時(shí)的方式:classpath 'com.example.clean:firstplug:1.0.0'
//三個(gè)參數(shù)
groupId 'com.example.clean'
artifactId 'firstplug'
version '1.0.0'
from components.java
}
}
}
publishing {
repositories {
maven {
// maven地址,可以是本地地址也可以是遠(yuǎn)程地址
url uri('C:/Android/repos')
}
}
}
最終build.gradle文件內(nèi)容如下:
apply plugin: 'groovy'
apply plugin: 'maven-publish'
dependencies {
//gradle sdk
implementation gradleApi()
//groovy sdk
implementation localGroovy()
}
publishing {
publications {
mavenJava(MavenPublication) {
//其他項(xiàng)目使用插件時(shí)的方式:classpath 'com.example.clean:firstplug:1.0.0'
//三個(gè)參數(shù)
groupId 'com.example.clean'
artifactId 'firstplug'
version '1.0.0'
from components.java
}
}
}
publishing {
repositories {
maven {
// maven地址伤溉,可以是本地地址也可以是遠(yuǎn)程地址
url uri('C:/Android/repos')
}
}
}
??同步gradle般码,在右側(cè)的gradle目錄中,找到clean下的publish任務(wù)乱顾,并運(yùn)行publish板祝,將插件上傳至maven庫(kù)。
??運(yùn)行成功后券时,在本地的repos目錄下可以找到上傳的插件
5、引用插件
??在項(xiàng)目的根build.gradle文件中伏伯,添加插件引用和maven庫(kù)地址橘洞,最終build.gradle文件內(nèi)容如下:
buildscript {
repositories {
google()
jcenter()
maven {//local maven repo path
url uri('C:/Android/repos')
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.example.clean:firstplug:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
同步gradle,在app module的build.gradle文件中添加插件说搅,如下:
//原文件的android插件
apply plugin: 'com.android.application'
//添加自定義插件炸枣,插件名即為com.example.firstplugin.properties文件名
apply plugin: 'com.example.firstplugin'
自定義插件名即為com.example.firstplugin.properties文件名,同步build.gradle弄唧,運(yùn)行app下的bulid任務(wù)
出現(xiàn)"clean plugin"适肠,即自定義插件中apply方法中輸出的日志,表示插件運(yùn)行成功套才。