Gradle 的許多功能都是透過外掛提供的,包括與 Gradle 一起發布的核心外掛、第三方外掛,以及在建置中定義的腳本外掛。

外掛會引入新的任務(例如 JavaCompile)、網域物件(例如 SourceSet)、慣例(例如將 Java 原始碼定位在 src/main/java),並擴充核心或其他外掛物件。

Gradle 中的外掛對於自動化常見的建置任務、與外部工具或服務整合,以及根據特定專案需求調整建置流程至關重要。它們也作為組織建置邏輯的主要機制。

外掛的優點

在建置腳本中撰寫許多任務並複製設定區塊可能會很混亂。與直接將邏輯新增到建置腳本相比,外掛提供了多項優點

  • 促進可重複使用性:減少在專案中重複類似邏輯的需求。

  • 增強模組化:允許更模組化和有組織的建置腳本。

  • 封裝邏輯:將命令式邏輯分開,讓建置腳本更具宣告性。

外掛分發

您可以利用 Gradle 和 Gradle 社群的外掛,或建立自己的外掛。

外掛有下列三種取得方式

  1. 核心外掛 - Gradle 開發並維護一組 核心外掛

  2. 社群外掛 - 在遠端儲存庫中分享的 Gradle 外掛,例如 Maven 或 Gradle 外掛入口

  3. 本機外掛 - Gradle 讓使用者能夠使用 API 建立自訂外掛。

外掛類型

外掛可以實作為二進位外掛預編譯腳本外掛腳本外掛

二進位外掛

二進位外掛是編譯外掛,通常以 Java 或 Kotlin DSL 編寫,並封裝為 JAR 檔案。它們使用 plugins {} 區塊套用至專案。與腳本外掛或預編譯腳本外掛相比,它們提供更好的效能和可維護性。

預編譯腳本外掛

預編譯腳本外掛是 Groovy DSL 或 Kotlin DSL 腳本,編譯並分發為封裝在函式庫中的 Java 類別檔案。它們使用 plugins {} 區塊套用至專案。它們提供一種在專案間重複使用複雜邏輯的方式,並允許更佳地組織建置邏輯。

腳本外掛

腳本外掛是 Groovy DSL 或 Kotlin DSL 腳本,使用 apply from: 語法直接套用至 Gradle 建置腳本。它們在建置腳本中內嵌套用,以新增功能或自訂建置程序。它們易於使用。

外掛通常從腳本外掛開始(因為它們易於撰寫)。然後,隨著程式碼變得更有價值,它會移轉至二進位外掛,以便在多個專案或組織間輕鬆測試和分享。

使用外掛

若要使用外掛中封裝的建置邏輯,Gradle 需要執行兩個步驟。首先,它需要解析外掛,然後它需要套用外掛至目標,通常是 專案

  1. 解析外掛表示找出包含特定外掛的 JAR 正確版本,並將其加入指令碼類別路徑。一旦解析外掛,其 API 便可在建置指令碼中使用。指令碼外掛會自行解析,因為它們會從套用時提供的特定檔案路徑或 URL 中解析。作為 Gradle 發行版一部分提供的核心二進制外掛會自動解析。

  2. 套用外掛表示在專案上執行外掛的 Plugin.apply(T)

建議使用 外掛 DSL,以便一次解析並套用外掛。

解析外掛

Gradle 提供 核心外掛(例如 JavaPluginGroovyPluginMavenPublishPlugin 等)作為其發行版的一部分,這表示它們會自動解析。

核心外掛會使用外掛名稱在建置指令碼中套用

plugins {
    id «plugin name»
}

例如

build.gradle
plugins {
    id("java")
}

非核心外掛必須在套用之前解析。非核心外掛會以建置檔案中的唯一 ID 和版本進行識別

plugins {
    id «plugin id» version «plugin version»
}

並且必須在設定檔中指定外掛的位置

settings.gradle
pluginManagement {
    repositories {
        gradlePluginPortal()
    }
    maven {
        url 'https://maven.example.com/plugins'
    }
}

解析和套用外掛還有其他考量因素

# 若要 使用 例如

1

核心社群本機外掛套用至特定專案。

建置檔案中的 plugins 區塊

plugins {
  id("org.barfuin.gradle.taskinfo") version "2.1.0"
}

2

將共用的 核心社群本機外掛套用至多個子專案。

buildSrc 目錄中的建置指令碼

plugins {
    id("org.barfuin.gradle.taskinfo") version "2.1.0"
}
repositories {
    jcenter()
}
dependencies {
    implementation(Libs.Kotlin.coroutines)
}

3

套用 核心社群本機外掛,針對建置指令碼本身

建置檔案中的 buildscript 區塊

buildscript {
  repositories {
    maven {
      url = uri("https://plugins.gradle.org/m2/")
    }
  }
  dependencies {
    classpath("org.barfuin.gradle.taskinfo:gradle-taskinfo:2.1.0")
  }
}
plugins {
  id("org.barfuin.gradle.taskinfo") version "2.1.0"
}

4

套用 本機指令碼外掛。

建置檔案中的舊版 apply() 方法

apply(plugin = "org.barfuin.gradle.taskinfo")
apply<MyPlugin>()

1. 使用 plugins{} 區塊套用外掛

外掛 DSL 提供簡潔且便利的方式來宣告外掛相依性。

外掛區塊設定 PluginDependenciesSpec 的執行個體

plugins {
    application                                     // by name
    java                                            // by name
    id("java")                                      // by id - recommended
    id("org.jetbrains.kotlin.jvm") version "1.9.0"  // by id - recommended
}

核心 Gradle 外掛很特別,因為它們提供簡短名稱,例如核心 JavaPluginjava

若要套用核心外掛,可以使用簡短的 名稱

build.gradle.kts
plugins {
    java
}
build.gradle
plugins {
    id 'java'
}

所有其他二進制外掛都必須使用外掛 ID 的完全限定形式(例如,com.github.foo.bar)。

若要套用 Gradle 外掛入口 中的社群外掛,必須使用完全限定的外掛 ID,也就是全球唯一的識別碼

build.gradle.kts
plugins {
    id("com.jfrog.bintray") version "1.8.5"
}
build.gradle
plugins {
    id 'com.jfrog.bintray' version '1.8.5'
}

請參閱 PluginDependenciesSpec,以取得有關使用外掛 DSL 的更多資訊。

外掛 DSL 的限制

外掛 DSL 為使用者提供方便的語法,並讓 Gradle 能夠快速判斷使用哪些外掛。這讓 Gradle 能夠

  • 最佳化外掛類別的載入和重複使用。

  • 提供編輯器有關建置指令碼中潛在屬性和值的詳細資訊。

不過,DSL 要求外掛必須以靜態方式定義。

plugins {} 區塊機制和「傳統」apply() 方法機制之間有一些關鍵差異。還有一些限制和可能的限制。

受限語法

plugins {} 區塊不支援任意程式碼。

它受到約束,必須是冪等(每次產生相同的結果)且沒有副作用(Gradle 可以隨時安全執行)。

格式為

build.gradle.kts
plugins {
    id(«plugin id»)                             (1)
    id(«plugin id») version «plugin version»    (2)
}
1 針對核心 Gradle 外掛或建置指令碼中已有的外掛
2 針對需要解析的二進制 Gradle 外掛
build.gradle
plugins {
    id «plugin id»                            (1)
    id «plugin id» version «plugin version»   (2)
}
1 針對核心 Gradle 外掛或建置指令碼中已有的外掛
2 針對需要解析的二進制 Gradle 外掛

其中 «plugin id»«plugin version» 為字串。

其中 «plugin id»«plugin version» 必須是常數、字面字串。

plugins{} 區塊也必須是建置指令碼中的頂層陳述式。它不能巢狀在其他結構內(例如,if 陳述式或 for 迴圈)。

僅限於建置指令碼和設定檔

plugins{} 區塊只能用於專案的建置指令碼 build.gradle(.kts)settings.gradle(.kts) 檔。它必須出現在任何其他區塊之前。它不能用於指令碼外掛或初始化指令碼。

套用外掛至所有子專案

假設您有一個 多專案建置,您可能想要將外掛套用至建置中部分或全部的子專案,但不要套用至根目錄專案。

雖然 plugins{} 區塊的預設行為是立即 resolve apply 外掛程式,但你可以使用 apply false 語法告訴 Gradle 不要將外掛程式套用至目前的專案。然後,在子專案的建置指令碼中使用沒有版本的 plugins{} 區塊

settings.gradle.kts
include("hello-a")
include("hello-b")
include("goodbye-c")
build.gradle.kts
plugins {
    id("com.example.hello") version "1.0.0" apply false
    id("com.example.goodbye") version "1.0.0" apply false
}
hello-a/build.gradle.kts
plugins {
    id("com.example.hello")
}
hello-b/build.gradle.kts
plugins {
    id("com.example.hello")
}
goodbye-c/build.gradle.kts
plugins {
    id("com.example.goodbye")
}
settings.gradle
include 'hello-a'
include 'hello-b'
include 'goodbye-c'
build.gradle
plugins {
    id 'com.example.hello' version '1.0.0' apply false
    id 'com.example.goodbye' version '1.0.0' apply false
}
hello-a/build.gradle
plugins {
    id 'com.example.hello'
}
hello-b/build.gradle
plugins {
    id 'com.example.hello'
}
goodbye-c/build.gradle
plugins {
    id 'com.example.goodbye'
}

你也可以封裝外部外掛程式的版本,方法是使用你自己的 慣例外掛程式 組合建置邏輯。

2. 從 buildSrc 目錄套用外掛程式

buildSrc 是 Gradle 專案根目錄中一個選用的目錄,其中包含用於建置主專案的建置邏輯(例如外掛程式)。只要專案的 buildSrc 目錄中存在已定義 ID 的外掛程式,你就可以套用這些外掛程式。

以下範例說明如何將定義在 buildSrc 中的外掛程式實作類別 my.MyPlugin 繫結至 ID "my-plugin"

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

gradlePlugin {
    plugins {
        create("myPlugins") {
            id = "my-plugin"
            implementationClass = "my.MyPlugin"
        }
    }
}
buildSrc/build.gradle
plugins {
    id 'java-gradle-plugin'
}

gradlePlugin {
    plugins {
        myPlugins {
            id = 'my-plugin'
            implementationClass = 'my.MyPlugin'
        }
    }
}

然後可以按 ID 套用外掛程式

build.gradle.kts
plugins {
    id("my-plugin")
}
build.gradle
plugins {
    id 'my-plugin'
}

3. 使用 buildscript{} 區塊套用外掛程式

buildscript 區塊用於

  1. 建置專案所需的全球 dependenciesrepositories(套用至子專案)。

  2. 宣告哪些外掛程式可供 建置指令碼(在 build.gradle(.kts) 檔案本身)使用。

因此,當你想要在建置指令碼本身中使用函式庫時,你必須使用 buildScript 在指令碼類別路徑中新增這個函式庫

import org.apache.commons.codec.binary.Base64

buildscript {
    repositories {  // this is where the plugins are located
        mavenCentral()
        google()
    }
    dependencies { // these are the plugins that can be used in subprojects or in the build file itself
        classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' // used in the task below
        classpath 'com.android.tools.build:gradle:4.1.0' // used in subproject
    }
}

tasks.register('encode') {
    doLast {
        def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
        println new String(encodedString)
    }
}

你可以在需要它的子專案中套用全球宣告的相依性

plugins {
    id 'com.android.application'
}

可以透過將外掛程式新增至建置指令碼類別路徑,然後套用外掛程式,將以外部 jar 檔案發佈的二進位外掛程式新增至專案。

可以如 建置指令碼的外部相依性 中所述,使用 buildscript{} 區塊將外部 jar 新增至建置指令碼類別路徑

build.gradle.kts
buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5")
    }
}

apply(plugin = "com.jfrog.bintray")
build.gradle
buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
    }
}

apply plugin: 'com.jfrog.bintray'

4. 使用舊版 apply() 方法套用指令碼外掛程式

指令碼外掛程式是一個臨時外掛程式,通常會寫在與 build.gradle 檔案位於同一個目錄中,並在該檔案中套用。它會使用 舊版套用方法 套用

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        println("Plugin ${this.javaClass.simpleName} applied on ${project.name}")
    }
}

apply<MyPlugin>()

我們來看一個寫在名為 other.gradle 的檔案中的外掛程式基本範例,這個檔案位於與 build.gradle 檔案相同的目錄中

public class Other implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // Does something
    }
}

首先,使用以下方式匯入外部檔案

apply from: 'other.gradle'

然後您可以套用它

apply plugin: Other

指令碼外掛程式會自動解析,且可以從本機檔案系統或遠端套用指令碼

build.gradle.kts
apply(from = "other.gradle.kts")
build.gradle
apply from: 'other.gradle'

檔案系統位置相對於專案目錄,而遠端指令碼位置則以 HTTP URL 指定。可以將多個指令碼外掛程式(任何形式)套用至特定目標。

外掛程式管理

pluginManagement{} 區塊用於設定外掛程式解析的存放庫,並定義在建置指令碼中套用的外掛程式版本限制。

pluginManagement{} 區塊可以在 settings.gradle(.kts) 檔案中使用,其中它必須是檔案中的第一個區塊

settings.gradle.kts
pluginManagement {
    plugins {
    }
    resolutionStrategy {
    }
    repositories {
    }
}
rootProject.name = "plugin-management"
settings.gradle
pluginManagement {
    plugins {
    }
    resolutionStrategy {
    }
    repositories {
    }
}
rootProject.name = 'plugin-management'

此區塊也可以在 初始化指令碼 中使用

init.gradle.kts
settingsEvaluated {
    pluginManagement {
        plugins {
        }
        resolutionStrategy {
        }
        repositories {
        }
    }
}
init.gradle
settingsEvaluated { settings ->
    settings.pluginManagement {
        plugins {
        }
        resolutionStrategy {
        }
        repositories {
        }
    }
}

自訂外掛程式存放庫

預設情況下,plugins{} DSL 會從公開的 Gradle 外掛程式入口網站 解析外掛程式。

許多建置作者也希望從私人的 Maven 或 Ivy 存放庫解析外掛程式,因為它們包含專有的實作詳細資料,或希望更能控制哪些外掛程式可供其建置使用。

若要指定自訂外掛程式存放庫,請在 pluginManagement{} 內部使用 repositories{} 區塊

settings.gradle.kts
pluginManagement {
    repositories {
        maven(url = "./maven-repo")
        gradlePluginPortal()
        ivy(url = "./ivy-repo")
    }
}
settings.gradle
pluginManagement {
    repositories {
        maven {
            url './maven-repo'
        }
        gradlePluginPortal()
        ivy {
            url './ivy-repo'
        }
    }
}

這會指示 Gradle 在解析外掛程式時,先查看 ../maven-repo 中的 Maven 存放庫,然後如果在 Maven 存放庫中找不到外掛程式,再查看 Gradle 外掛程式入口網站。如果您不希望搜尋 Gradle 外掛程式入口網站,請略過 gradlePluginPortal() 行。最後,將會查看 ../ivy-repo 中的 Ivy 存放庫。

外掛程式版本管理

pluginManagement{} 內部的 plugins{} 區塊允許在單一位置定義建置的所有外掛程式版本。然後,外掛程式可以透過 plugins{} 區塊以 ID 套用至任何建置指令碼。

設定外掛版本的方式有一個好處,就是 pluginManagement.plugins{} 沒有與建置指令碼 plugins{} 區塊相同的 受限語法。這允許外掛版本從 gradle.properties 取得,或透過其他機制載入。

透過 pluginManagement 管理外掛版本

settings.gradle.kts
pluginManagement {
  val helloPluginVersion: String by settings
  plugins {
    id("com.example.hello") version "${helloPluginVersion}"
  }
}
build.gradle.kts
plugins {
    id("com.example.hello")
}
gradle.properties
helloPluginVersion=1.0.0
settings.gradle
pluginManagement {
  plugins {
        id 'com.example.hello' version "${helloPluginVersion}"
    }
}
build.gradle
plugins {
    id 'com.example.hello'
}
gradle.properties
helloPluginVersion=1.0.0

外掛版本從 gradle.properties 載入,並在設定指令碼中設定,允許外掛新增至任何專案,而不需要指定版本。

外掛解析規則

外掛解析規則允許您修改 plugins{} 區塊中提出的外掛要求,例如變更請求的版本或明確指定實作人工製品座標。

如需新增解析規則,請在 pluginManagement{} 區塊內使用 resolutionStrategy{}

settings.gradle.kts
pluginManagement {
    resolutionStrategy {
        eachPlugin {
            if (requested.id.namespace == "com.example") {
                useModule("com.example:sample-plugins:1.0.0")
            }
        }
    }
    repositories {
        maven {
            url = uri("./maven-repo")
        }
        gradlePluginPortal()
        ivy {
            url = uri("./ivy-repo")
        }
    }
}
settings.gradle
pluginManagement {
    resolutionStrategy {
        eachPlugin {
            if (requested.id.namespace == 'com.example') {
                useModule('com.example:sample-plugins:1.0.0')
            }
        }
    }
    repositories {
        maven {
            url './maven-repo'
        }
        gradlePluginPortal()
        ivy {
            url './ivy-repo'
        }
    }
}

這會指示 Gradle 使用指定的實作人工製品,而不是從外掛 ID 到 Maven/Ivy 座標的內建預設對應。

自訂 Maven 和 Ivy 外掛儲存庫必須包含 外掛標記人工製品 和實作外掛的人工製品。請參閱 Gradle 外掛開發外掛,以取得更多關於發佈外掛至自訂儲存庫的資訊。

請參閱 PluginManagementSpec,以取得使用 pluginManagement{} 區塊的完整文件。

外掛標記人工製品

由於 plugins{} DSL 區塊只允許透過其全球唯一外掛 idversion 屬性宣告外掛,因此 Gradle 需要一種方式來查詢外掛實作人工製品的座標。

為此,Gradle 會尋找座標為 plugin.id:plugin.id.gradle.plugin:plugin.version 的外掛標記人工製品。此標記需要有對實際外掛實作的依賴關係。發佈這些標記會由 java-gradle-plugin 自動執行。

例如,sample-plugins 專案中的下列完整範例顯示如何使用 java-gradle-pluginmaven-publishivy-publish 外掛結合,將 com.example.hello 外掛和 com.example.goodbye 外掛同時發佈到 Ivy 和 Maven 儲存庫。

build.gradle.kts
plugins {
    `java-gradle-plugin`
    `maven-publish`
    `ivy-publish`
}

group = "com.example"
version = "1.0.0"

gradlePlugin {
    plugins {
        create("hello") {
            id = "com.example.hello"
            implementationClass = "com.example.hello.HelloPlugin"
        }
        create("goodbye") {
            id = "com.example.goodbye"
            implementationClass = "com.example.goodbye.GoodbyePlugin"
        }
    }
}

publishing {
    repositories {
        maven {
            url = uri(layout.buildDirectory.dir("maven-repo"))
        }
        ivy {
            url = uri(layout.buildDirectory.dir("ivy-repo"))
        }
    }
}
build.gradle
plugins {
    id 'java-gradle-plugin'
    id 'maven-publish'
    id 'ivy-publish'
}

group 'com.example'
version '1.0.0'

gradlePlugin {
    plugins {
        hello {
            id = 'com.example.hello'
            implementationClass = 'com.example.hello.HelloPlugin'
        }
        goodbye {
            id = 'com.example.goodbye'
            implementationClass = 'com.example.goodbye.GoodbyePlugin'
        }
    }
}

publishing {
    repositories {
        maven {
            url layout.buildDirectory.dir("maven-repo")
        }
        ivy {
            url layout.buildDirectory.dir("ivy-repo")
        }
    }
}

在範例目錄中執行 gradle publish 會建立下列 Maven 儲存庫配置(Ivy 配置類似)

plugin markers

舊版外掛應用程式

隨著 plugins DSL 的推出,使用者幾乎沒有理由使用舊版外掛應用程式的方法。如果建置作者無法使用外掛 DSL,因為它目前運作方式的限制,我們在此提供說明。

build.gradle.kts
apply(plugin = "java")
build.gradle
apply plugin: 'java'

可以使用外掛 ID 應用外掛。在上述情況中,我們使用簡稱「java」來應用 JavaPlugin

除了使用外掛 ID,也可以透過指定外掛類別來應用外掛

build.gradle.kts
apply<JavaPlugin>()
build.gradle
apply plugin: JavaPlugin

上述範例中的 JavaPlugin 符號是指 JavaPlugin。這個類別不需要特別匯入,因為 org.gradle.api.plugins 套件會自動匯入所有建置指令碼(請參閱 預設匯入)。

此外,需要附加 ::class 後綴字元來識別 Kotlin 中的類別文字,而不是 Java 中的 .class

此外,不需要附加 .class 來識別 Groovy 中的類別文字,因為它在 Java 中是這樣。

使用版本目錄

當專案使用版本目錄時,可以在應用時透過別名來參照外掛。

我們來看一個簡單的版本目錄

gradle/libs.versions.toml
[versions]
intellij-plugin = "1.6"

[plugins]
jetbrains-intellij = { id = "org.jetbrains.intellij", version.ref = "intellij-plugin" }

然後可以使用 alias 方法將外掛應用到任何建置指令碼

build.gradle.kts
plugins {
    alias(libs.plugins.jetbrains.intellij)
}
jetbrains-intellij 可用作 Gradle 產生的安全存取器:jetbrains.intellij

下一步: 了解如何撰寫外掛 >>