本文內容大部分來自 Gradle 官方文檔,英文 OK 的同窗能夠直接看官方文檔。 本文示例代碼已放在 zjxstar 的 GitHub。html
提及 Gradle 插件,不得不感嘆 Gradle 的設計很是棒。 Gradle 自己提供基本的概念以及核心框架,而其餘的場景邏輯均可以經過插件擴展的方式來實現。對於 Android 開發來講,經常使用的插件就是 Android Gradle 插件和 Java 插件了,咱們會在下一篇文章中詳細介紹 Android 插件。java
本文主要學習 Gradle 插件的基礎知識以及如何編寫自定義插件。android
Gradle 插件一般用來封裝一些可重用的編譯邏輯,能夠用來擴展項目的功能,幫助項目在構建過程當中處理一些特殊邏輯。git
總之,咱們只要根據插件約定的接口,使用它提供的任務、方法或者擴展,就能夠幫助咱們進行項目構建。github
Gradle 中的插件種類分爲兩種,一種是腳本插件,另外一種是二進制插件。而應用插件的方式也有多種,下面咱們詳細介紹。api
所謂的腳本插件就是咱們自定義的以 .gradle 爲後綴的腳本文件,嚴格意義上來講,它只是一個可執行腳本。應用它就是把整個腳本加載到主 build.gradle 腳本中,從而輔助構建。應用方式以下:網絡
apply from: '腳本文件名' // 好比:apply from: 'project_task_examples.gradle'
複製代碼
它不只能夠應用本地腳本,也能夠應用網絡上的腳本,這樣的話,就必須使用 HTTP URL 了。閉包
舉例說明:app
在前兩章的 Project 和 Task 的學習中,咱們在 app 模塊的 build.gradle 文件中寫了不少示例,咱們把這些示例都提到一個單獨的 gradle 腳本中,而後在 build.gradle 中應用它。新的腳本文件命名: project_task_examples.gradle ,只須要使用 apply from: 'project_task_examples.gradle' 應用便可。框架
雖然它不算真正的插件,但也不能忽視它的做用,它是腳本文件模塊化的基礎。咱們能夠把龐大的腳本文件進行分塊、分段整理,拆分紅一個個共用的、職責分明的文件,而後使用 apply from
應用它們。這樣可讓咱們的腳本更加清晰、簡單、方便和快捷。
二進制插件是實現了 org.gradle.api.Plugin
接口的插件(通常都是打包在 jar 裏獨立發佈),它們擁有 plugin id ,這個 id 是插件全局惟一的標識或名稱。咱們須要經過
apply plugin: 'plugin id'
複製代碼
的方式應用二進制插件。好比 Android 的 Application 插件,咱們經過 Android Studio 建立 Android 工程時,在 app 模塊中會自動經過 apply plugin: 'com.android.application' 來引入 Application 插件。
對於 Gradle 自帶的核心插件都有一個容易記的短名,好比 Java 插件,經過 apply plugin:'java' 應用。其實它對應的類型是 org.gradle.api.plugins.JavaPlugin
,因此還能夠經過該類型進行應用:apply plugin:org.gradle.api.plugins.JavaPlugin 。因爲包 org.gradle.api.plugins 是默認導入的,因此咱們能夠去掉包名直接寫爲: apply plugin:JavaPlugin 。
其實 apply 方法有重載方法:
void apply(Closure var1);
void apply(Action<? super ObjectConfigurationAction> var1);
void apply(Map<String, ?> var1);
複製代碼
以前使用的是傳入 Map 參數的方式,咱們也能夠換成閉包的方式。
apply {
plugin 'java'
}
複製代碼
plugins DSL 是一種新的插件應用方式,Gradle 2.1 以上版本纔可使用。它的語法以下:
plugins {
id «plugin id» // (1)
id «plugin id» version «plugin version» [apply «false»] // (2)
}
複製代碼
方式(1)是提供給 Gradle 核心插件或者構建腳本中已有的插件的。方式(2)提供給須要解析的二進制插件,這些插件要託管在 plugins.gradle.org/ 網站上。
示例:
plugins {
id 'java'
}
plugins {
id 'com.jfrog.bintray' version '0.4.1'
}
複製代碼
固然,這種使用方式有必定的限制:
插件的類型和應用方式就介紹到這,下面咱們要學習如何自定義插件,來知足本身的業務邏輯。
自定義插件的關鍵點就是要實現 org.gradle.api.Plugin
接口,重寫 apply 方法來實現本身的業務邏輯。本講中使用的示例都是構建 Task 的簡單示例,感興趣的同窗的能夠自行深刻。
這裏有三種方式來承載自定義插件的代碼:構建腳本、buildSrc 項目、獨立項目。
咱們能夠直接在構建腳本中編寫自定義插件的代碼。 這樣作的好處是插件能夠自動編譯幷包含在構建腳本的類路徑中,而無需執行任何操做。 可是,這樣定義的插件在構建腳本以外是不可見的,即沒法在其定義的構建腳本以外重用該插件。
示例:
/* 自定義插件:直接在腳本文件中定義,其侷限性較大 */
// app的build.gradle文件中
// 定義一個Extension類用來接收腳本傳的參數
class CustomExtensionA {
String message = 'Hello Custom PluginA'
// 還能夠定義其餘配置參數
String greeter = 'Welcome Gradle Plugin'
}
// 定義一個自定義插件類,實現Plugin接口
class CustomPluginA implements Plugin<Project> {
@Override
void apply(Project target) {
// 將Extension註冊給Plugin
def extension = target.extensions.create('customA', CustomExtensionA)
// 定義一個任務
target.task('CustomPluginTaskA') {
doFirst {
println 'this is custom plugin A task A'
}
doLast {
// 使用Extension傳入的參數
println extension.message
println extension.greeter
}
}
}
}
複製代碼
例子中,咱們建立一個 CustomPluginA 類,實現 Plugin 接口,重寫 apply 方法。在 apply 方法中使用 project 建立一個名爲 CustomPluginTaskA 的任務。該插件還能夠接受擴展,即定義了一個 CustomExtensionA 類,裏面有 message 和 greeter 兩個屬性。在 apply 方法中,經過 project.extensions.create(擴展名, 擴展類) 就能夠完成自定義擴展的註冊。
應用該插件只須要在 build.gradle 文件中使用 apply plugin 引入便可。
// 使用插件CustomPluginA,這裏必須使用插件類名,而不是字符串
// 使用gradlew -q CustomPluginTaskA查看插件是否生效
apply plugin: CustomPluginA
// 配置CustomExtensionA,須要使用註冊名,這裏是customA
customA.message = 'Hi from PluginA'
複製代碼
引入插件後,能夠像運行普通任務同樣經過命令運行插件中定義的 Task 。至於擴展的使用,只需使用擴展名聲明對應屬性便可。
咱們能夠在工程裏新建一個名爲 buildSrc 的模塊來開發自定義插件,其過程和寫 Android Library 相似。buildSrc 模塊中的代碼會自動被 Gradle 加載,Gradle 將負責編譯和測試插件並使其在構建腳本的類路徑中可用。 這種方式定義的插件對於構建中的每一個構建腳本都是可見的。 可是,它在構建以外是不可見的,所以沒法在其定義的構建以外重用該插件。
新建 buildSrc 模塊:
該模塊很是簡單,只須要有 src/main/groovy 目錄用來存放源代碼便可(由於使用的 Groovy 語言編寫,因此是 groovy,若是使用 java 或者 kotlin ,換成對應目錄便可)。
在 build.gradle 腳本中依賴 gradleApi 和 Groovy 插件。
// 依賴groovy插件
plugins {
id 'groovy'
}
dependencies {
implementation gradleApi()
implementation localGroovy()
}
複製代碼
接着就是寫代碼了,這個過程和「構建腳本」小節中同樣,只是將代碼放在了 groovy 文件中而已。
// 在單獨的groovy文件中定義插件類
class CustomPluginB implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('CustomPluginTaskB') {
doFirst {
println 'This is custom plugin TaskB'
}
}
}
}
複製代碼
最後,就是在 app 模塊中引入該插件。
/* 自定義插件:引用在buildSrc模塊中定義的插件,使用插件類名的全限定名 */
// 使用gradlew -q CustomPluginTaskB查看插件是否生效
apply plugin: com.zjx.happy.plugin.CustomPluginB
複製代碼
因爲構建過程當中 Gradle 會自動加載 buildSrc 模塊中的代碼,因此直接使用插件類的全限定名便可。
咱們能夠爲插件建立單獨的項目。將該項目發佈成一個 JAR ,就能夠在多個地方使用它。這種方式是比較經常使用的。
首先,和 buildSrc 項目同樣建立一個新模塊,模塊名沒有要求。
和 buildSrc 不一樣的是,它多出了一個 resources 資源目錄。一樣的,這個模塊裏也要依賴 gradleApi 和 Groovy 插件。
而後,在 groovy 目錄下完成代碼的編寫。這裏依然只是寫個簡單示例。
class CustomPluginC implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('CustomPluginTaskC') {
doFirst {
println 'This is Custom Plugin TaskC'
}
}
}
}
複製代碼
至此,插件的核心已經準備好了,如今要給這個插件設置一個 plugin id 。須要在 resources 目錄下,建立 META-INF 目錄。而後在 META-INF 目錄下再建立一個 gradle-plugins 目錄。( 注意: 這裏建立目錄時請逐級建立。不要經過一次性輸入 META-INF.gradle-plugins 的目錄名方式建立,由於 resources 目錄沒法像代碼目錄那樣自動識別包名並分級,它只會建立一個目錄,這樣是不正確的。)
目錄建立好後,咱們須要在該目錄下,新建一個 properties 文件,而文件名就是插件的 plugin id 。該 properties 文件中須要聲明插件的實現類,語法以下:
# 建立該目錄時必定要注意,要一級一級的建立,先建立META-INF,再建立gradle-plugins,而不是直接META-INF.gradle-plugins
# 由於不是src的目錄,因此沒法自動識別 . 號
# implementation-class是固定的,等號右邊是插件實現類的全限定類名
implementation-class=com.zjx.happy.plugin.CustomPluginC
複製代碼
詳細目錄結構如圖:
本示例中的插件的 plugin id 就是 com.happy.custompluginc 。那麼 plugin id 有哪些規範呢?
插件準備好後,咱們要將其發佈出去,通常使用 Maven 。
// build.gradle中
apply plugin: 'maven' // 引入 maven 插件
repositories {
mavenCentral()
}
// 將該插件上傳到本地Maven庫
group='com.happy.plugin'
version='1.0.0'
// 經過gradlew :customPlugin:uploadArchives命令上傳
uploadArchives {
repositories {
mavenDeployer {
//本地的Maven地址設置爲../repos
repository(url: uri('../repos'))
}
}
}
複製代碼
使用 gradlew :customPlugin:uploadArchives 命令上傳。示例中會在工程目錄下建立 repos 目錄,裏面存放了 customPlugin 的 jar 包和 pom 信息。
如何應用獨立模塊自定義的插件呢?其方法和 Android 插件同樣。
在根 build.gradle 文件中聲明插件依賴:
dependencies {
// 這是Android插件
classpath 'com.android.tools.build:gradle:3.3.1'
// 這是剛自定義的插件
classpath 'com.happy.plugin:customPlugin:1.0.0'
}
複製代碼
同步以後,就能夠在 app 模塊中使用 apply plugin 引入了。
/* 自定義插件:引用已經發布到Maven的插件 */
apply plugin: 'com.happy.custompluginc' // 這個plugin id就是properties文件的文件名
複製代碼
最後,使用命令 gradlew -q CustomPluginTaskC 驗證插件是否生效。
Gradle 插件相關的內容就這麼多,總體上看仍是很簡單的。如今社區中的第三方插件不少,咱們能夠根據業務須要適當引用。固然,咱們也徹底能夠本身實現適合業務的插件。通常 APM 類項目中 中就須要實現自定義插件來完成代碼的自動插樁,它須要利用到 Android 提供的 Gradle-api 中的 Transform 。後續的文章中咱們會學習 Transform 。