編譯自己的 Gradle 插件
前面幾節(jié)我們學習了 Gradle 的任務及命令,通過這幾節(jié)的學習我們已經(jīng)有了一定的 Gradle 基礎(chǔ),今天我們就來學習一下如何自定義一款 Gradle 插件。我們?yōu)槭裁匆远x Gradle 插件呢?那當然是為了我們開發(fā)方便呀。如果吃力不討好誰會去做呢。下面我們進入正題。
Gradle 插件主要分為兩類:腳本插件和對象插件。下面我們來看下它們的區(qū)別。
1. 腳本插件
腳本插件就是我們在.gradle
文件 [例如 demo.gradle ]中定義自己的編譯任務。在項目中的build.gradle
文件中通過apply from:'demo.gradle'
就可以使用這個腳本插件。
下面我們以輸出項目名稱為例子,來簡單學習腳本插件,一般我們將腳本插件寫在項目的根目錄下,項目目錄結(jié)構(gòu)如下:
1.1 demo.gradle
我們在這里定義一個任務 showProjectName 輸出,調(diào)用該插件的 module 的名稱:
// demo.gradle
task showProjectName{
doLast {
println("$project.name")
}
}
1.2 在 build.gradle 中引用該插件
我們需要在對應模塊的 build.gradle 文件中引用插件,這里我們在 app 模塊下的 build.gradle中引用,由于demo.gradle 在 build.gradle 的父目錄一級。所以我們需要在前面加上../
,具體如下:
//這行命令需再最前面
apply from: '../demo.gradle'
1.3 運行該任務
我們運行這個任務 ,前面定義 Gradle 任務的時候講過最好使用駝峰命名,我們可以使用以下命令。
//使用任務全拼
$ gradle showProjectName
//使用簡寫方式
$ gradle sPN
輸出結(jié)果如下,我們看到那種結(jié)果都會疏忽當前模塊的名稱 app。
2. 對象插件
所謂對象插件就是指我們定義一個實現(xiàn)org.gradle.api.Plugin
接口的類。這個類就是我們所謂的對象插件。該類必須實現(xiàn) Plugin 接口的apply
方法。
編寫 Gradle 對象插件的方式有以下 3 種:
- 在 gradle 文件中添加腳本: 這種方式就是直接在我們的 build.gradle 文件中添加 Groovy 腳本 。
- 在 buildSrc 目錄下創(chuàng)建: 這種方式是在根目錄下添加 buildSrc 的一個子模塊。
- 在獨立項目中創(chuàng)建: 這種方式是創(chuàng)建一個單獨的項目,寫一個 Gradle 插件,發(fā)布后別的項目都可以使用。
2.1 在 gradle 文件中添加腳本
我們還是以上面的輸出模塊名稱為例,我們定義一個PluginInGradleScript
的類實現(xiàn)Plugin
接口:
//app 模塊下build.gradle
class PluginInGradleScript implements Plugin<Project> {
@Override
void apply(Project target) {
target.task('showProjectName'){
doLast {
println("PluginInGradleScript:Module Name is $target.name")
}
}
}
}
引用該插件,引用自定義插件時我們使用apply plugin
語句,記住這句還是要在 build.gradle 的最上面兩行,具體如下:
apply plugin: PluginInGradleScript
我們到這里就已經(jīng)將插件引用到項目中了,下面我們還是執(zhí)行命令,看看定義的插件能否正常輸出 module name。
$ gradle showProjectName
> Task :app:showProjectName
PluginInGradleScript:Module Name is app
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.0.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
如上所示,我們就成功定義了一個對象插件,這種定義方式適合項目中比較小巧的,簡單的一些功能插件。較復雜的還是不建議這種定義方式。
2.2 添加 buildSrc 子項目
我們首先需要在項目的根目錄下創(chuàng)建一個 buildSrc 的模塊,這樣如果項目中有多個模塊就可以重復使用插件了。
創(chuàng)建 buildSrc 模塊
首先,我們需要創(chuàng)建一個 Java Library 名字叫做 buildSrc。因為插件我們需要使用 Groovy 語言寫,所以我們需要將 main 目錄下的 java 目錄修改為 groovy 目錄。
修改后如下所示:
修改 build.gradle
因為我們創(chuàng)建的是 Java Libiary,這里我們使用的是 Groovy 語言所以,buildSrc 的 build.gradle 文件我們需要修改為如下:
//buildSrc/build.gradle
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
CustomPluginInBuildSrc.groovy 文件
緊接著我們需要定義 Plugin 插件,我們還是以輸出 module name 為例:
package com.bthvi.buildsrc
import org.gradle.api.Project
import org.gradle.api.Plugin
class CustomPluginInBuildSrc implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('showCustomPluginInBuildSrc') {
doLast {
println("InBuildSrc: Module Name is $project.name")
}
}
}
}
在 app/build.gradle 中引用
我們引用可以使用如下兩種方式引用:
第一種: 我們直接按照類名和包名路徑引用
import com.bthvi.buildsrc.CustomPluginInBuildSrc
apply plugin: CustomPluginInBuildSrc
//或者直接引用全路徑
apply plugin: com.bthvi.buildsrc.CustomPluginInBuildSrc
第二種: 我們按照如下目錄創(chuàng)建 resources 目錄及 xxx.properties 文件,這里的 xxx 就是我們要引用的插件。我們這里創(chuàng)建 myplugin.properties。并將id對應的 Plugin 實現(xiàn)類全路徑配置如下:
implementation-class=com.bthvi.buildsrc.CustomPluginInBuildSrc
使用插件
下面我們使用 gradle 命令來調(diào)用這個插件,我們直接使用gradle showCustomPluginInBuildSrc
來執(zhí)行這個任務。
D:\AndroidProjects\CustomGradlePlugins>gradle showCustomPluginInBuildSrc
> Task :app:showCustomPluginInBuildSrc
InBuildSrc: Module Name is app
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.0.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
Tips: 我們可能會遇到
'buildSrc' cannot be used as a project name as it is a reserved name
這個錯誤,如下圖所示。
這個錯誤的原因是因為,我們在 setting.gradle 中配置了 buildSrc,我們把 setting.gradle 中配置的 buildSrc 刪掉就 OK 了。
3. 單獨的項目中
上面的 buildSrc 模塊下定義 Gradle 插件也只是僅僅限制于當前的項目的各個模塊間引用,如果我們想要在多個模塊間復用同一個插件,我們就需要單獨創(chuàng)建一個工程,并將我們定義的 Gradle 插件發(fā)布到 Maven。
單獨工程中定義插件跟在 buildSrc 中是一樣的,唯一不同的就是我們需要配置上傳,這里我們上傳到自己的本地目錄’loccal’中,這里我從創(chuàng)建一個名字為 CustomPluginDemo,目錄結(jié)構(gòu)如下:
我們這里修改 build.gradle 文件如下:
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile gradleApi()
compile localGroovy()
}
group = 'com.bthvi.mplugin'
version = '1.0.0'
uploadArchives {
repositories {
mavenDeployer {
repository(url: uri('D:/local'))
}
}
}
這里我們配置將插件上傳至 D 盤的local
目錄下,配置完成我們同步后會看到如下:
我們點擊左邊三角形執(zhí)行編譯并上傳任務,執(zhí)行完成后我們會在 D 盤local
目錄下看到如下目錄結(jié)構(gòu):
這樣就代表我們可以在項目中使用此插件了,但是我們需要將本地的 Maven 地址加入項目,在最外層 build.gradle 中配置如下:
buildscript {
repositories {
maven {
url uri('D:/local')
}
google()
jcenter()
}
dependencies {
classpath 'com.bthvi.mplugin:CustomPluginDemo:1.0.1'
classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven {
url uri('D:/local')
}
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
然后像 buildSrc 一樣我們就可以在 app 下引用自定義的插件myplugin
了。
apply plugin: 'myplugin'
我們執(zhí)行gradle showCustomPluginInBuildSrc
為了區(qū)分,我們修改了輸出語句println("In Projet: Module Name is $project.name")
,我們執(zhí)行后會看到如下輸出:
D:\AndroidProjects\CustomGradlePlugins>gradle showCustomPluginInBuildSrc
> Task :app:showCustomPluginInBuildSrc
In Projet: Module Name is app
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.0.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
4. 小結(jié)
本節(jié),我們從簡單到復雜,首先介紹了腳本插件,然后我們介紹了對象插件,先是在腳本中直接定義,但是這種只適用于當前模塊,如果一個項目中多個模塊想要共用一個插件,我們就需要在 buildSrc 目錄下新建一個插件供多個模塊復用。但是如果想要多個項目共用一個插件,我們就需要單獨定義一個 Gradle 項目,并且上傳到 Maven,我們多個項目使用的時候直接添加 Maven 就好。本文中直接上傳到本地磁盤了,有興趣的同學可以下來嘗試將自己的插件上傳到 Maven 服務器。