Gradle 附帶一系列強大的核心系統,例如相依性管理、任務執行和專案設定。但它能做的其他所有事情都是由外掛提供的。

外掛封裝特定任務或整合的邏輯,例如編譯程式碼、執行測試或部署成品。透過套用外掛,使用者可以輕鬆地為其建置流程新增新功能,而無需從頭開始撰寫複雜的程式碼。

這種基於外掛的方法讓 Gradle 變得輕量且模組化。它也促進程式碼再利用和可維護性,因為外掛可以在專案或組織內共用。

在閱讀本章節之前,建議您先閱讀 學習基礎知識 並完成 教學課程

外掛簡介

外掛可以從 Gradle 或 Gradle 社群取得。但當使用者想要整理其建置邏輯或需要現有外掛未提供的特定建置功能時,他們可以開發自己的外掛。

因此,我們區分三種不同類型的外掛

  1. 核心外掛 - 來自 Gradle 的外掛。

  2. 社群外掛 - 來自 Gradle 外掛入口網站 或公開儲存庫的外掛。

  3. 本機或自訂外掛 - 您自己開發的外掛。

核心外掛

術語核心外掛是指 Gradle 發行版中的一部分外掛,例如 Java 函式庫外掛。它們總是可用的。

社群外掛程式

術語社群外掛程式是指已發佈到 Gradle 外掛程式入口網站(或其他公開儲存庫)的外掛程式,例如 Spotless 外掛程式

本機或自訂外掛程式

術語本機或自訂外掛程式是指您為自己的建置撰寫的外掛程式。

自訂外掛程式

有三種類型的自訂外掛程式

# 類型 位置 最有可能 好處

1

建置指令碼和指令碼外掛

建置指令碼或指令碼

本機外掛程式

外掛程式會自動編譯並包含在建置指令碼的類別路徑中。

2

預編譯指令碼外掛

buildSrc 資料夾或 複合 建置

慣例外掛程式

外掛程式會自動編譯、測試,並在建置指令碼的類別路徑中提供。外掛程式對建置使用的每個建置指令碼都可見。

3

二進位外掛

獨立專案

共享外掛程式

會產生並發佈外掛程式 JAR。外掛程式可以在多個建置中使用,並與他人分享。

建置指令碼和指令碼外掛程式

建置指令碼外掛程式通常是小型本機外掛程式,以建置檔案撰寫,適用於單一建置或專案的特定任務,而且不需要在多個專案中重複使用。不建議使用建置指令碼外掛程式,但許多其他形式的外掛程式都是從建置指令碼外掛程式演變而來的。

若要建立 Gradle 外掛程式,您需要在其中一個建置檔案中撰寫一個實作 Plugin 介面的類別。

下列範例建立一個 GreetingPlugin,它會將 hello 任務新增到專案中

build.gradle.kts
class GreetingPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.task("hello") {
            doLast {
                println("Hello from the GreetingPlugin")
            }
        }
    }
}

// Apply the plugin
apply<GreetingPlugin>()
build.gradle
class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println 'Hello from the GreetingPlugin'
            }
        }
    }
}

// Apply the plugin
apply plugin: GreetingPlugin
$ gradle -q hello
Hello from the GreetingPlugin

Project 物件會在 apply() 中傳遞為參數,外掛程式可以使用它來根據需要設定專案(例如新增任務、設定相依性等)。

指令碼外掛程式類似於建置指令碼外掛程式,不過外掛程式定義只會在一個獨立的指令碼中進行,然後使用 apply(from = " ")apply from: '' 將它套用至建置檔案:不建議使用指令碼外掛程式。

other.gradle.kts
class GreetingScriptPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.task("hi") {
            doLast {
                println("Hi from the GreetingScriptPlugin")
            }
        }
    }
}

// Apply the plugin
apply<GreetingScriptPlugin>()
other.gradle
class GreetingScriptPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hi') {
            doLast {
                println 'Hi from the GreetingScriptPlugin'
            }
        }
    }
}

// Apply the plugin
apply plugin: GreetingScriptPlugin
build.gradle.kts
apply(from = "other.gradle.kts")
build.gradle
apply from: 'other.gradle'
$ gradle -q hi
Hi from the GreetingScriptPlugin

預編譯指令碼外掛

預編譯指令碼外掛會在執行前編譯成類別檔案並封裝成 JAR。這些外掛使用 Groovy 或 Kotlin DSL,而非純 Java、Kotlin 或 Groovy。它們最適合用作在專案間共用建置邏輯的慣例外掛,或用來整齊組織建置邏輯。

若要建立預編譯指令碼外掛,您可以

  1. 使用 Gradle 的 Kotlin DSL - 外掛是 .gradle.kts 檔案,並套用 id("kotlin-dsl")

  2. 使用 Gradle 的 Groovy DSL - 外掛是 .gradle 檔案,並套用 id("groovy-gradle-plugin")

若要套用預編譯指令碼外掛,您需要知道它的 ID。ID 是根據外掛指令碼的檔案名稱和它(選用)的套件宣告而來的。

例如,指令碼 src/main/*/java-library.gradle(.kts) 的外掛 ID 是 java-library(假設它沒有套件宣告)。同樣地,src/main/*/my/java-library.gradle(.kts) 的外掛 ID 是 my.java-library,只要它的套件宣告是 my

預編譯指令碼外掛名稱有兩個重要的限制

  • 它們不能以 org.gradle 開頭。

  • 它們不能與核心外掛同名。

當外掛套用至專案時,Gradle 會建立外掛類別的執行個體,並呼叫執行個體的 Plugin.apply() 方法。

套用該外掛的每個專案內會建立 Plugin 的新執行個體。

我們將 GreetingPlugin 指令碼外掛改寫為預編譯指令碼外掛。由於我們使用 Groovy 或 Kotlin DSL,檔案基本上就變成了外掛。原始指令碼外掛只是建立一個會列印問候語的 hello 工作,這也是我們將在預編譯指令碼外掛中執行的動作

buildSrc/src/main/kotlin/GreetingPlugin.gradle.kts
tasks.register("hello") {
    doLast {
        println("Hello from the convention GreetingPlugin")
    }
}
buildSrc/src/main/groovy/GreetingPlugin.gradle
tasks.register("hello") {
    doLast {
        println("Hello from the convention GreetingPlugin")
    }
}

現在可以使用其 ID 在其他子專案的建置中套用 GreetingPlugin

app/build.gradle.kts
plugins {
    application
    id("GreetingPlugin")
}
app/build.gradle
plugins {
    id 'application'
    id('GreetingPlugin')
}
$ gradle -q hello
Hello from the convention GreetingPlugin

慣例外掛

慣例外掛通常是一個預編譯的腳本外掛,它會使用您自己的慣例(例如預設值)來設定現有的核心和社群外掛,例如使用 java.toolchain.languageVersion = JavaLanguageVersion.of(17) 設定 Java 版本。慣例外掛也用於強制執行專案標準並協助簡化建置流程。它們可以套用和設定外掛、建立新的工作和擴充功能、設定相依性,以及更多功能。

我們舉一個包含三個子專案的建置範例:一個是 data-model、一個是 database-logic,還有一個是 app 程式碼。專案結構如下

.
├── buildSrc
│   ├── src
│   │   └──...
│   └── build.gradle.kts
├── data-model
│   ├── src
│   │   └──...
│   └── build.gradle.kts
├── database-logic
│   ├── src
│   │   └──...
│   └── build.gradle.kts
├── app
│   ├── src
│   │   └──...
│   └── build.gradle.kts
└── settings.gradle.kts

database-logic 子專案的建置檔案如下

database-logic/build.gradle.kts
plugins {
    id("java-library")
    id("org.jetbrains.kotlin.jvm") version "1.9.23"
}

repositories {
    mavenCentral()
}

java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain(11)
}

// More build logic
database-logic/build.gradle
plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm' version '1.9.23'
}

repositories {
    mavenCentral()
}

java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

// More build logic

我們套用 java-library 外掛,並加入 org.jetbrains.kotlin.jvm 外掛以支援 Kotlin。我們也設定 Kotlin、Java、測試等。

我們的建置檔案開始變大了…​

我們套用的外掛越多,設定的外掛越多,檔案就會越大。appdata-model 子專案的建置檔案中也會有重複的部分,特別是在設定常見擴充功能時,例如設定 Java 版本和 Kotlin 支援。

為了解決這個問題,我們使用慣例外掛。這讓我們可以避免在每個建置檔案中重複設定,並讓建置指令碼更簡潔且易於維護。在慣例外掛中,我們可以封裝任意的建置設定或自訂建置邏輯。

若要開發慣例外掛,我們建議使用 buildSrc,它代表一個完全獨立的 Gradle 建置。buildSrc 有自己的設定檔,用於定義此建置的相依性位置。

我們在 buildSrc/src/main/kotlin 目錄中加入一個名為 my-java-library.gradle.kts 的 Kotlin 腳本。或者,在 buildSrc/src/main/groovy 目錄中加入一個名為 my-java-library.gradle 的 Groovy 腳本。我們將 database-logic 建置檔案中的所有外掛套用和設定都放入其中

buildSrc/src/main/kotlin/my-java-library.gradle.kts
plugins {
    id("java-library")
    id("org.jetbrains.kotlin.jvm")
}

repositories {
    mavenCentral()
}

java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain(11)
}
buildSrc/src/main/groovy/my-java-library.gradle
plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm'
}

repositories {
    mavenCentral()
}

java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

檔案 my-java-library 的名稱就是我們全新外掛的 ID,我們現在可以在所有子專案中使用它。

為什麼 id 'org.jetbrains.kotlin.jvm' 的版本不見了?請參閱 套用外部外掛至預編譯腳本外掛

database-logic 建置檔案變得更簡單了,因為我們移除了所有多餘的建置邏輯,並套用我們的慣例 my-java-library 外掛

database-logic/build.gradle.kts
plugins {
    id("my-java-library")
}
database-logic/build.gradle
plugins {
    id('my-java-library')
}

此慣例外掛讓我們能輕鬆地在所有建置檔案間共用一般設定。任何修改都能在同一個地方進行,簡化維護。

二進制外掛

Gradle 中的二進制外掛是建置為獨立 JAR 檔案的外掛,並使用建置指令碼中的 plugins{} 區塊套用至專案。

讓我們將 GreetingPlugin 移至獨立專案,以便我們能發布並與其他人共用。外掛基本上從 buildSrc 資料夾移至稱為 greeting-plugin 的自訂建置。

您可以從 buildSrc 發布外掛,但這不是建議做法。準備好發布的外掛應位於其自訂建置中。

greeting-plugin 僅是一個 Java 專案,用於產生包含外掛類別的 JAR。

將外掛打包並發布至儲存庫最簡單的方式是使用 Gradle 外掛開發外掛。此外掛提供必要的任務和設定(包括外掛元資料),用於將您的指令碼編譯成可在其他建置中套用的外掛。

以下是使用 Gradle 外掛開發外掛的 greeting-plugin 專案的簡單建置指令碼

build.gradle.kts
plugins {
    `java-gradle-plugin`
}

gradlePlugin {
    plugins {
        create("simplePlugin") {
            id = "org.example.greeting"
            implementationClass = "org.example.GreetingPlugin"
        }
    }
}
build.gradle
plugins {
    id 'java-gradle-plugin'
}

gradlePlugin {
    plugins {
        simplePlugin {
            id = 'org.example.greeting'
            implementationClass = 'org.example.GreetingPlugin'
        }
    }
}

如需有關發布外掛的更多資訊,請參閱 發布外掛

專案相對於設定相對於初始化外掛

在本節中使用的範例中,外掛接受 專案 類型作為類型參數。或者,外掛可以接受類型為 設定 的參數,以在設定指令碼中套用,或接受類型為 Gradle 的參數,以在初始化指令碼中套用。

這些類型外掛之間的差異在於其套用範圍

專案外掛

專案外掛是套用至建置中特定專案的外掛。它可以自訂建置邏輯、新增任務和設定專案特定設定。

設定外掛

設定外掛是套用於 settings.gradlesettings.gradle.kts 檔案的外掛。它可以設定套用至整個建置的設定,例如定義建置中包含哪些專案、設定建置指令碼儲存庫,以及將一般設定套用至所有專案。

初始化外掛

初始化外掛是一種套用於 init.gradleinit.gradle.kts 檔案的外掛。它可以設定套用於機器上所有 Gradle 建置的設定,例如設定 Gradle 版本、設定預設存放庫或套用常見外掛至所有建置。