關(guān)于Gradle Transform API 的詳細(xì)分析我之前有一篇文章Android Gradle Transform 詳解已經(jīng)講到了,這里不再重復(fù),直接開始上手?jǐn)]代碼,還沒看過前面一篇博客的同學(xué)建議先去看看,好幫助理解。
1、 新建 Android Library Module :plugin,清空plugin的build.gradle文件中的內(nèi)容,然后修改成如下內(nèi)容
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
implementation gradleApi() //gradle sdk
implementation localGroovy() //groovy sdk
implementation 'com.android.tools.build:gradle:3.4.1'
}
repositories {
jcenter()
}
uploadArchives {
repositories.mavenDeployer {
//本地倉庫路徑,以放到項(xiàng)目根目錄下的 repo 的文件夾為例
repository(url: uri('../repo'))
//groupId ,自行定義,組織名或公司名
pom.groupId = 'com.jokerwan'
//artifactId,自行定義,項(xiàng)目名或模塊名
pom.artifactId = 'autotrack.android'
//插件版本號(hào)
pom.version = '1.0.0'
}
}
我們這里是發(fā)布plugin插件到本地倉庫,上面配置的groupId、artifactId和version屬性能容都是可以自定義的,當(dāng)應(yīng)用程序引用這個(gè)插件時(shí)會(huì)用到這些信息。通過repositories屬性,可以把uri配置在本地目錄,這樣就可以把maven設(shè)置成本地倉庫,我們目前把倉庫配置到當(dāng)前Project根目錄下的repo目錄。
2、 刪除plugin/src/main目錄下的所有文件,新建groovy目錄
因?yàn)椴寮覀冇玫氖莋roovy語言開發(fā)的,所以需要放到groovy目錄下。接著再groovy目錄下新建一個(gè)package com.jokerwan.demo.plugin來存放Transform類文件
3、 創(chuàng)建Transform類
在包com.jokerwan.demo.plugin下創(chuàng)建JokerWanTransform.groovy類,直接new一個(gè)file,名稱為“JokerWanTransform.groovy”,代碼如下:
package com.jokerwan.demo.plugin
import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
class JokerWanTransform extends Transform {
private static Project project
private static final String NAME = "JokerWanAutoTrack"
JokerWanTransform(Project project) {
this.project = project
}
@Override
String getName() {
return NAME
}
/**
* 需要處理的數(shù)據(jù)類型,有兩種枚舉類型
* CLASSES 代表處理的 java 的 class 文件,RESOURCES 代表要處理 java 的資源
* @return
*/
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
/**
* 指 Transform 要操作內(nèi)容的范圍,官方文檔 Scope 有 7 種類型:
* 1. EXTERNAL_LIBRARIES 只有外部庫
* 2. PROJECT 只有項(xiàng)目?jī)?nèi)容
* 3. PROJECT_LOCAL_DEPS 只有項(xiàng)目的本地依賴(本地jar)
* 4. PROVIDED_ONLY 只提供本地或遠(yuǎn)程依賴項(xiàng)
* 5. SUB_PROJECTS 只有子項(xiàng)目。
* 6. SUB_PROJECTS_LOCAL_DEPS 只有子項(xiàng)目的本地依賴項(xiàng)(本地jar)。
* 7. TESTED_CODE 由當(dāng)前變量(包括依賴項(xiàng))測(cè)試的代碼
* @return
*/
@Override
Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
@Override
boolean isIncremental() {
return false
}
static void printCopyRight() {
println()
println("******************************************************************************")
println("****** ******")
println("****** 歡迎使用 JokerWanTransform 編譯插件 ******")
println("****** ******")
println("******************************************************************************")
println()
}
@Override
void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
printCopyRight()
TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()
// Transform 的 inputs 有兩種類型,一種是目錄,一種是 jar 包,要分開遍歷
transformInvocation.inputs.each { TransformInput input ->
input.jarInputs.each { JarInput jarInput ->
// 處理jar
processJarInput(jarInput, outputProvider)
}
input.directoryInputs.each { DirectoryInput directoryInput ->
// 處理源碼文件
processDirectoryInput(directoryInput, outputProvider)
}
}
}
void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {
// 重命名輸出文件(同目錄copyFile會(huì)沖突)
def jarName = jarInput.name
def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length() - 4)
}
File dest = outputProvider.getContentLocation(
jarName + md5Name,
jarInput.getContentTypes(),
jarInput.getScopes(),
Format.JAR
)
// TODO do some transform
// 將 input 的目錄復(fù)制到 output 指定目錄
FileUtils.copyFile(jarInput.getFile(), dest)
}
void processDirectoryInput(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {
File dest = outputProvider.getContentLocation(
directoryInput.getName(),
directoryInput.getContentTypes(),
directoryInput.getScopes(),
Format.DIRECTORY
)
// TODO do some transform
// 將 input 的目錄復(fù)制到 output 指定目錄
FileUtils.copyDirectory(directoryInput.getFile(), dest)
}
}
我們?cè)?code>transform方法里面,先打印一個(gè)提示信息,然后分別遍歷目錄和jar包,在這里我們僅僅把所有的輸入文件拷貝到目標(biāo)目錄下,并沒有對(duì)文件進(jìn)行任何處理。這里需要注意的是,即使我們對(duì)文件沒有任何處理,任然需要將所有的輸入文件拷貝到目標(biāo)目錄下,否則下一個(gè)Task就沒有TansformInput了,如果我們將 input 的目錄復(fù)制到 output 指定目錄,最后會(huì)導(dǎo)致打包的apk缺少.class文件。
4、 創(chuàng)建plugin
在包com.jokerwan.demo.plugin下創(chuàng)建JokerWanPlugin.groovy類,并將JokerWanTransform類注冊(cè)進(jìn)去
class JokerWanPlugin implements Plugin<Project> {
void apply(Project project) {
AppExtension appExtension = project.extensions.findByType(AppExtension.class)
appExtension.registerTransform(new JokerWanTransform(project))
}
}
JokerWanPlugin實(shí)現(xiàn)了Plugin<Project>接口中的apply(Project project)方法,獲取一個(gè)appExtension對(duì)象,然后調(diào)用其registerTransform方法將JokerWanTransformNew的實(shí)例注冊(cè)進(jìn)去
5、 創(chuàng)建properties文件
在plugin/src/main目錄下新建目錄 resources/META-INF/gradle-plugins,接著在此目錄下新建文件com.jokerwan.android.properties,文件內(nèi)容如下:
implementation-class=com.jokerwan.demo.plugin.JokerWanPlugin
文件名com.jokerwan.android就是用來指定插件名稱的,apply該組件時(shí)會(huì)用到,即
apply plugin: 'com.jokerwan.android'
“=”號(hào)后面的內(nèi)容就是我們插件類JokerWanPlugin的全類名
6、 構(gòu)建plugin
執(zhí)行plugin的uploadArchives任務(wù)構(gòu)建plugin

構(gòu)建成功之后,在項(xiàng)目的根目錄會(huì)生成一個(gè)repo目錄,里面存放的就是plugin插件的目標(biāo)文件。構(gòu)建成功輸出信息如下:

7、 添加對(duì)插件的依賴
7.1、 修改項(xiàng)目根目錄下的build.gradle文件

7.2、 修改app/build.gradle文件

8、 構(gòu)建應(yīng)用程序
可以通過命令行進(jìn)行編譯
./gradlew assembleDebug
如果編譯沒有報(bào)錯(cuò)的話并且看到相應(yīng)的輸出信息,就可以說明上面定義的JokerWanTransform已經(jīng)成功運(yùn)行了。編譯成功輸出信息如下:
