四、使用Gradle插件
Gradle本身只是一個框架,它的核心部分在構建過程中起的作用實際上很小。真正起作用的步驟來自於插件,比如編譯Java代碼的功能就是由“java”插件提供。
在本章中,我們會詳細價紹如何使用Gradle的插件
4.1 插件能做些什麼
插件可以做的事情很多,比如:
- 擴展Gradle的功能
- 根據用戶的配置來做一些自定義的構建
- 增加構建多種具體項目的功能,如Android插件
使用插件有許多好處:
-
促進腳本的複用,可以減少相似的構建腳本
-
可以更好地組織項目結構
-
將具體的邏輯封裝起來,然後用聲明式的方式使用
4.2 插件的類型
4.2.1 腳本插件和二進制插件
Gradle的插件分爲兩種類型:腳本插件(script plugins)和二進制插件(binary plugins)。
腳本插件 就是額外的構建腳本,腳本插件通常用來對構建過程進行深度配置,同樣遵循聲明式的思想。腳本插件常常作爲另一個腳本文件(即*.gradle) 文件被放置在項目目錄中,以本地文件的形式應用插件。雖然腳本插件也可以放置在雲端,比如說共享倉庫jcenter,但不常用,一般共享的插件都是二進制插件。
二進制插件就是實現了Plugin
接口的類,可以用java、kotlin和groovy編寫,更容易進行測試,還可以被打包成jar包共享出去。
一個插件項目最開始寫的時候通常都是以腳本插件的形式,因爲它們更容易編寫,當項目變得更有價值之後再被遷移成二進制插件,這樣更容易測試以及共享。
4.2.2 核心插件和社區插件
Gradle的插件根據是否內置又分爲核心插件和社區插件,核心插件是Gradle必要的插件(如java
插件),核心插件隨着Gradle安裝已經解析好了,只需要應用即可;社區插件是共享在社區上的插件,在需要時才被解析到本地。
社區插件會被共享在一些在線倉庫中,例如jcenter、Maven倉庫等,Gradle還提供了一個專門共享Gradle插件的倉庫:Gradle plugin portal,Gradle官方推薦將插件共享在這裏。
4.3 Gradle插件的三種實現方式
(本小節僅簡單介紹,實現Gradle插件的方法詳見“自定義Gradle插件”章節)
4.3.1 腳本插件
可以直接在build.gradle
中編寫一個實現了org.gradle.api.plugins
接口的類, 這個類就是一個插件。另外,這種方式編寫的插件就是上文所提的腳本插件
4.3.2 在buildSrc中編寫插件類
Gradle提供了一種在現有項目中編寫二進制插件的方法,依舊遵循聲明式的思想。
二進制插件可以用Java、Kotlin、Groovy多種語言編寫,例如使用的是Groovy語言,那麼就創建目錄rootProjectDir/buildSrc/src/main/groovy
,如果是kotlin則爲.../kotlin
,Groovy則爲.../groovy
。Gradle會自動編譯這些目錄下的插件,並且將它們解析,使得在項目的所有構建腳本中都可以應用這些目錄下的插件。
4.3.3 獨立項目
還可以爲你的插件單獨建立一個項目,這個項目可以被打包成一個jar包,可以實現更好的複用,還可以分享到在線倉庫成爲社區插件,給別的項目使用。
4.4 使用插件兩步走
使用插件Gradle的插件大致上分爲兩部,第一步是解析插件,第二步是應用插件。
解析插件 就是找到插件的正確版本,因爲Gradle的插件允許有多個版本同時存在,在選擇插件時要同時指定插件名和版本。對於二進制插件,因爲並不指定它們所在的路徑,Gradle要去指定的倉庫根據插件名和版本號尋找對應的插件,並解析到本地;而對於腳本插件,它是“自解析”的,因爲配置腳本插件時直接指定了它的路徑。
應用插件 就是在解析插件完成之後將插件的腳本內容應用到項目的構建中,對於二進制插件,會在此時調用它的apply
方法(這個方法定義在Plugin接口中)。
4.5 傳統apply語法
使用插件有兩種語法,一種是傳統的apply語法,另一種是DSL語法。我們先介紹傳統的apply語法。
每個插件都有一個id,我們可以通過指定插件的id的方式來應用插件,以應用java
插件爲例:
//build.gradle
apply plugin: 'java'
也可以直接指定插件的實現類的類名
//build.gradle
apply plugin: JavaPlugin
對於內置插件,我們可以直接通過上述的apply
語法應用插件,指定類名時也不需要前綴(org.gradle.api.plugins)以及.class
後綴。
但對於社區插件,我們還需要先解析插件。解析插件使用的是buildscript{}
語法塊,語法規則如下:
//build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1'
}
}
apply plugin: 'com.jfrog.bintray'
裏面還有兩個子塊:
repositories{}
語法塊,用於指定倉庫,有以下常用選項:mavenLocal()
:本地Maven倉庫( ${user.home}/.m2/repository )mavenCentral()
:中央Maven倉庫( http://repo1.maven.org/maven2 )maven { url 'https://...' }
:可用於Maven私服、鏡像服務器等ivy {url "../local-repo"}
:本地的ivy倉庫ivy {url "http://repo.mycompany.com/repo"}
:遠程的ivy倉庫google()
:google倉庫(https://maven.google.com)
dependencies{}
語法塊,用於指定要使用的插件,由classpath
關鍵字指定,格式爲:classpath 'group:name:version'
4.6 plugins DSL語法
Gradle鼓勵將Gradle插件共享在它的Gradle plugin portal上,對於上面的插件Gradle還提供了簡潔的應用插件的語法,這就是“plugins DSL"語法。
因爲解析插件和應用插件通常都同時使用,所以plugins DSL
語法默認同時對插件進行解析和應用,核心插件和社區插件的使用方式略有不同,核心插件只需要指定插件名,以java插件爲例:
//build.gradle
plugins {
id 'java'
}
//build.gradle.kts
plugins {
java
}
社區插件還需要指定版本
//build.gradle
plugins {
id 'com.jfrog.bintray' version '0.4.1'
}
//build.gradle.kts
plugins {
id("com.jfrog.bintray") version "0.4.1"
}
DSL語法存在着一些限制,首先是語法規則比較嚴格,這也是出於聲明式的思想,語法規則如下:
//build.gradle
plugins {
id «plugin id» ①
id «plugin id» version «plugin version» [apply «false»] ②
}
//① 適用於核心插件,或者已經解析好的插件、或者buildSrc中的插件
//② 適用於社區插件,因爲DSL語法默認同時解析和應用插件,加上apply «false»可以只解析不應用
//apply false的具體用法見後續章節
而且DSL語法只能用於構建腳本中,不能用於腳本插件中,也不能用於settings.gradle
、init script
,不過Gradle官方說會在之後的版本移除這種限制(筆者當前版本是5.6.3)
4.7 Plugin Management語法塊
4.7.1 基本語法
pluginManagement{}
語法塊是專門用於管理整個項目插件的,只能出現在settings.gradle
文件或”初始化腳本“中,並且在settings.gradle
文件中pluginManagement{}
必須是文件中的第一個塊。
語法格式如下(限於篇幅,僅以groovy舉例,kotlin語法見手冊P313):
//build.gradle
pluginManagement {
plugins {
}
resolutionStrategy {
}
repositories {
}
}
//init.gradle
settingsEvaluated { settings ->
settings.pluginManagement {
plugins {
}
resolutionStrategy {
}
repositories {
}
}
}
4.7.2 設置插件的來源倉庫
默認情況下,plugins DSL語法會從Gradle plugin portal去解析插件,但許多插件開發者喜歡使用私有的Maven或Ivy倉庫,爲了指定使用的插件倉庫,Gradle提供了repositories{}
語法塊,放在pluginManagement
語法塊中使用,用於管理整個項目使用的插件倉庫。
語法規則如下(以本地路徑爲例,如果使用網絡資源就將路徑替換成http url):
//build.gradle
pluginManagement {
repositories {
maven {
url '../maven-repo'
}
gradlePluginPortal()
ivy {
url '../ivy-repo'
}
}
}
//注:指定的倉庫順序就是Gradle尋找插件順序的優先級,本例中會先
//去maven倉庫嘗試解析所需插件,如果找不到再去gradlePluginPortal
//如果再找不到,最後再去ivy倉庫
4.7.3 插件版本管理
Gradle提供了plugins{}
語法塊,用於pluginManagement
語法塊中,用於統一指定整個倉庫使用的某個插件的版本。
使用這種方式管理插件的版本有一些好處,例如在多projects構建中很有用,因爲在多projects構建中統一每個子project依賴的插件版本很有必要;另外,前面提過,DSL語法在build.gradle
有嚴格的限制,但是在settings.gradle
中語法卻比較寬鬆,這允許它從gradle.properties
文件中去獲取版本。
在根目錄下的settings.gradle
指定了插件的版本後,在build.gradle
中只需要指定插件的id即可,插件版本配置在gradle.properties
中。
使用示例如下:
//settings.gradle
pluginManagement {
plugins {
id 'org.gradle.sample.hello' version "${helloPluginVersion}"
}
}
//build.gradle
plugins {
id 'org.gradle.sample.hello'
}
//gradle.properties
helloPluginVersion=1.0.0