如果 Gradle 或 Gradle 社群沒有提供專案所需具備的特定功能,建立您自己的外掛程式可能是一個解決方案。

此外,如果您發現自己重複子專案的組建邏輯,而且需要更好的方式來組織它,自訂外掛程式可以提供幫助。

自訂外掛程式

外掛程式是實作 Plugin 介面的任何類別。以下範例是最直接的外掛程式,一個「hello world」外掛程式

build.gradle.kts
import org.gradle.api.Plugin
import org.gradle.api.Project

abstract class SamplePlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.create("SampleTask") {
            println("Hello world!")
        }
    }
}

腳本外掛程式

許多外掛程式會從在組建腳本中編碼的腳本外掛程式開始。這提供了一種在組建外掛程式時快速建立原型和實驗的簡單方式。讓我們來看一個範例

build.gradle.kts
// Define a task
abstract class CreateFileTask : DefaultTask() {                                     (1)
    @get:Input
    abstract val fileText: Property<String>                                         (2)

    @Input
    val fileName = "myfile.txt"

    @OutputFile
    val myFile: File = File(fileName)

    @TaskAction
    fun action() {
        myFile.createNewFile()
        myFile.writeText(fileText.get())
    }
}

// Define a plugin
abstract class MyPlugin : Plugin<Project> {                                         (3)
    override fun apply(project: Project) {
        tasks {
            register("createFileTask", CreateFileTask::class) {
                group = "from my plugin"
                description = "Create myfile.txt in the current directory"
                fileText.set("HELLO FROM MY PLUGIN")
            }
        }
    }
}

// Apply the local plugin
apply<MyPlugin>()                                                                   (4)
1 建立 DefaultTask() 的子類別。
2 在任務中使用延遲組態。
3 延伸 org.gradle.api.Plugin 介面。
4 套用腳本外掛程式。

1. 建立 DefaultTask() 的子類別

首先,透過子類化 DefaultTask() 建立一個任務。

abstract class CreateFileTask : DefaultTask() { }

這個簡單的任務會將一個檔案加入到我們應用程式的根目錄。

2. 使用延遲配置

Gradle 有個概念稱為延遲配置,它允許在實際設定任務輸入和輸出之前,就可以參考它們。這是透過 Property 類型別來完成的。

abstract val fileText: Property<String>

這種機制的優點之一是,你可以在檔案名稱甚至尚未決定之前,將一個任務的輸出檔案連結到另一個任務的輸入檔案。Property 類別也知道它連結到哪個任務,讓 Gradle 能夠自動加入必要的任務相依性。

3. 擴充 org.gradle.api.Plugin 介面

接著,建立一個新的類別,擴充 org.gradle.api.Plugin 介面。

abstract class MyPlugin : Plugin<Project> {
    override fun apply() {}
}

你可以在 apply() 方法中加入任務和其他邏輯。

4. 套用腳本外掛

最後,在建置腳本中套用本地的外掛。

apply<MyPlugin>()

當在建置腳本中套用 MyPlugin 時,Gradle 會呼叫自訂 MyPlugin 類別中定義的 fun apply() {} 方法。

這會讓外掛可用於應用程式。

不建議使用腳本外掛。腳本外掛提供一種快速建置建置邏輯的簡便方式,在將其移轉到更永久的解決方案(例如慣例外掛二進位外掛)之前。

慣例外掛

慣例外掛是一種在 Gradle 中封裝並重複使用常見建置邏輯的方式。它們允許你為專案定義一組慣例,然後將這些慣例套用至其他專案或模組。

上面的範例已重新寫成一個儲存在 buildSrc 中的慣例外掛

buildSrc/src/main/kotlin/MyConventionPlugin.kt
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.File

abstract class CreateFileTask : DefaultTask() {
    @get:Input
    abstract val fileText: Property<String>

    @Input
    val fileName = project.rootDir.toString() + "/myfile.txt"

    @OutputFile
    val myFile: File = File(fileName)

    @TaskAction
    fun action() {
        myFile.createNewFile()
        myFile.writeText(fileText.get())
    }
}

class MyConventionPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.register("createFileTask", CreateFileTask::class.java) {
            group = "from my plugin"
            description = "Create myfile.txt in the current directory"
            fileText.set("HELLO FROM MY PLUGIN")
        }
    }
}

可以使用 gradlePlugin{} 區塊給予外掛一個 id,以便在根目錄中參考它

buildSrc/build.gradle.kts
gradlePlugin {
    plugins {
        create("my-convention-plugin") {
            id = "com.gradle.plugin.my-convention-plugin"
            implementationClass = "com.gradle.plugin.MyConventionPlugin"
        }
    }
}

gradlePlugin{} 區塊定義專案建置的外掛。有了新建立的 id,就可以相應地在其他建置腳本中套用外掛

build.gradle.kts
plugins {
    application
    id("com.gradle.plugin.my-convention-plugin") // Apply the new plugin
}

二進位外掛

二進制外掛是實作於已編譯語言並封裝為 JAR 檔案的外掛。它是作為相依性來解析,而非從原始碼編譯。

對於大多數使用案例,慣例外掛必須不頻繁地更新。讓每個開發人員在開發過程中執行外掛建置是浪費,我們可以改為將它們分發為二進制相依性。

有兩種方法可以將上述範例中的慣例外掛更新為二進制外掛。

  1. 使用 複合建置

    settings.gradle.kts
    includeBuild("my-plugin")
  2. 將外掛發布至儲存庫

    build.gradle.kts
    plugins {
        id("com.gradle.plugin.myconventionplugin") version "1.0.0"
    }

請參閱 開發外掛章節 以了解更多資訊。