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

此外,如果您發現自己在子專案之間重複建置邏輯,並且需要更好的方式來組織它,慣例外掛程式可以提供協助。

腳本外掛程式

外掛程式是任何實作 Plugin 介面的類別。例如,這是一個「hello world」外掛程式

build.gradle.kts
abstract class SamplePlugin : Plugin<Project> { (1)
    override fun apply(project: Project) {  (2)
        project.tasks.register("ScriptPlugin") {
            doLast {
                println("Hello world from the build file!")
            }
        }
    }
}

apply<SamplePlugin>() (3)
build.gradle
class SamplePlugin implements Plugin<Project> { (1)
    void apply(Project project) {   (2)
        project.tasks.register("ScriptPlugin") {
            doLast {
                println("Hello world from the build file!")
            }
        }
    }
}

apply plugin: SamplePlugin (3)
1 擴展 org.gradle.api.Plugin 介面。
2 覆寫 apply 方法。
3 apply 外掛程式至專案。

1. 擴展 org.gradle.api.Plugin 介面

建立一個擴展 Plugin 介面的類別

build.gradle.kts
abstract class SamplePlugin : Plugin<Project> {
}
build.gradle
class SamplePlugin implements Plugin<Project> {
}

2. 覆寫 apply 方法

apply() 方法中新增 task 和其他邏輯

build.gradle.kts
override fun apply() {

}
build.gradle
void apply(Project project) {

}

3. apply 外掛程式至您的專案

SamplePlugin 套用至您的專案時,Gradle 會呼叫定義的 fun apply() {} 方法。這會將 ScriptPlugin task 新增至您的專案

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

請注意,這是一個簡單的 hello-world 範例,並不反映最佳實務

不建議使用腳本外掛程式。

開發外掛程式的最佳實務是建立慣例外掛程式二進制外掛程式

預編譯腳本外掛程式

預編譯腳本外掛程式提供了一種快速原型設計和實驗的簡便方法。它們讓您可以使用 Groovy 或 Kotlin DSL 將建置邏輯打包為 *.gradle(.kts) 腳本檔案。這些腳本位於特定目錄中,例如 src/main/groovysrc/main/kotlin

若要套用一個,只需使用從腳本檔案名稱 (不含 .gradle) 衍生的 ID 即可。您可以將檔案本身視為外掛程式,因此您不需要在預編譯腳本中子類別化 Plugin 介面。

讓我們看看具有以下結構的範例

.
└── buildSrc
    ├── build.gradle.kts
    └── src
       └── main
          └── kotlin
             └── my-create-file-plugin.gradle.kts

我們的 my-create-file-plugin.gradle.kts 檔案包含以下程式碼

buildSrc/src/main/kotlin/my-create-file-plugin.gradle.kts
abstract class CreateFileTask : DefaultTask() {
    @get:Input
    abstract val fileText: Property<String>

    @Input
    val fileName = "myfile.txt"

    @OutputFile
    val myFile: File = File(fileName)

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

tasks.register<CreateFileTask>("createMyFileTaskInConventionPlugin") {
    group = "from my convention plugin"
    description = "Create myfile.txt in the current directory"
    fileText.set("HELLO FROM MY CONVENTION PLUGIN")
}
buildSrc/src/main/groovy/my-create-file-plugin.gradle
abstract class CreateFileTask extends DefaultTask {
    @Input
    abstract Property<String> getFileText()

    @Input
    String fileName = "myfile.txt"

    @OutputFile
    File getMyFile() {
        return new File(fileName)
    }

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

tasks.register("createMyFileTaskInConventionPlugin", CreateFileTask) {
    group = "from my convention plugin"
    description = "Create myfile.txt in the current directory"
    fileText.set("HELLO FROM MY CONVENTION PLUGIN")
}

預編譯腳本現在可以套用至任何子專案的 build.gradle(.kts) 檔案中

build.gradle.kts
plugins {
    id("my-create-file-plugin")  // Apply the pre-compiled convention plugin
    `kotlin-dsl`
}
build.gradle
plugins {
    id 'my-create-file-plugin' // Apply the pre-compiled convention plugin
    id 'groovy' // Apply the Groovy DSL plugin
}

來自外掛程式的 createFileTask task 現在可在您的子專案中使用。

二進制外掛程式

二進制外掛程式是以編譯語言實作並打包為 JAR 檔案的外掛程式。它作為相依性解析,而不是從原始碼編譯。

對於大多數使用案例,慣例外掛程式不需要頻繁更新。讓每位開發人員在其開發過程中執行外掛程式建置是浪費的,我們可以將它們作為二進制相依性發布。

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

  1. 使用 複合建置

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

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

讓我們選擇第二個解決方案。此外掛程式已使用 Kotlin 重新編寫,名為 MyCreateFileBinaryPlugin.kt。它仍然儲存在 buildSrc

buildSrc/src/main/kotlin/MyCreateFileBinaryPlugin.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 filePath = project.layout.settingsDirectory.file("myfile.txt").asFile.path

    @OutputFile
    val myFile: File = File(filePath)

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

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

可以使用 gradlePlugin{} 區塊發布外掛程式並賦予其 id,以便可以在根目錄中引用它

buildSrc/build.gradle.kts
group = "com.example"
version = "1.0.0"

gradlePlugin {
    plugins {
        create("my-binary-plugin") {
            id = "com.example.my-binary-plugin"
            implementationClass = "MyCreateFileBinaryPlugin"
        }
    }
}

publishing {
    repositories {
        mavenLocal()
    }
}
buildSrc/build.gradle
group = 'com.example'
version = '1.0.0'

gradlePlugin {
    plugins {
        create("my-binary-plugin") {
            id = "com.example.my-binary-plugin"
            implementationClass = "MyCreateFileBinaryPlugin"
        }
    }
}

publishing {
    repositories {
        mavenLocal()
    }
}

然後,可以在建置檔案中套用外掛程式

build.gradle.kts
plugins {
    id("my-create-file-plugin")  // Apply the pre-compiled convention plugin
    id("com.example.my-binary-plugin") // Apply the binary plugin
    `kotlin-dsl`
}
build.gradle
plugins {
    id 'my-create-file-plugin' // Apply the pre-compiled convention plugin
    id 'com.example.my-binary-plugin' // Apply the binary plugin
    id 'groovy' // Apply the Groovy DSL plugin
}

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