预编译脚本插件通常是一个 Kotlin 脚本,它被编译并作为打包在库中的 Java 类文件进行分发。这些脚本旨在用作二进制 Gradle 插件,并推荐作为约定插件使用。

约定插件通常是一个插件,它使用您自己的约定(即默认值)配置现有的核心插件和社区插件,例如使用 java.toolchain.languageVersion = JavaLanguageVersion.of(17) 设置 Java 版本。约定插件还用于强制执行项目标准并帮助简化构建过程。它们可以应用和配置插件、创建新的 Task 和扩展、设置依赖等。

设置插件 ID

预编译脚本的插件 ID 来自其文件名和可选的包声明。

例如,位于 src/main/groovy(或 src/main/kotlin)中且没有包声明、名为 code-quality.gradle(.kts) 的脚本将暴露为 code-quality 插件

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}
app/build.gradle.kts
plugins {
    id("code-quality")
}
buildSrc/build.gradle
plugins {
    id 'groovy-gradle-plugin'
}
app/build.gradle
plugins {
    id 'code-quality'
}

另一方面,位于 src/main/kotlin/my 中、包含包声明 my 且名为 code-quality.gradle.kts 的脚本将暴露为 my.code-quality 插件

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}
app/build.gradle.kts
plugins {
    id("my.code-quality")
}
Groovy 预编译脚本插件不能包含包。

使用扩展使插件可配置

扩展对象常用于插件中,用于向构建脚本暴露配置选项和额外功能。

当您应用一个定义了扩展的插件时,您可以访问该扩展对象并配置其属性或调用其方法,以自定义插件或插件提供的 Task 的行为。

一个 Project 有一个关联的 ExtensionContainer 对象,其中包含已应用于项目的所有插件的设置和属性。您可以通过向此容器添加扩展对象来为您的插件提供配置。

让我们更新 greetings 示例

buildSrc/src/main/kotlin/greetings.gradle.kts
// Create extension object
interface GreetingPluginExtension {
    val message: Property<String>
}

// Add the 'greeting' extension object to project
val extension = project.extensions.create<GreetingPluginExtension>("greeting")
buildSrc/src/main/groovy/greetings.gradle
// Create extension object
interface GreetingPluginExtension {
    Property<String> getMessage()
}

// Add the 'greeting' extension object to project
def extension = project.extensions.create("greeting", GreetingPluginExtension)

您可以使用 extension.message.set("Hi from Gradle,") 直接设置 message 属性的值。

然而,GreetingPluginExtension 对象作为项目属性可用,其名称与扩展对象相同。您现在可以像这样访问 message

buildSrc/src/main/kotlin/greetings.gradle.kts
// Where the<GreetingPluginExtension>() is equivalent to project.extensions.getByType(GreetingPluginExtension::class.java)
the<GreetingPluginExtension>().message.set("Hi from Gradle")
buildSrc/src/main/groovy/greetings.gradle
extensions.findByType(GreetingPluginExtension).message.set("Hi from Gradle")

如果您应用 greetings 插件,您可以在构建脚本中设置约定

app/build.gradle.kts
plugins {
    application
    id("greetings")
}

greeting {
    message = "Hello from Gradle"
}
app/build.gradle
plugins {
    id 'application'
    id('greetings')
}

configure(greeting) {
    message = "Hello from Gradle"
}

添加默认配置作为约定

在插件中,您可以使用 project 对象定义默认值,也称为约定

约定属性是使用默认值初始化的属性,但可以被覆盖

buildSrc/src/main/kotlin/greetings.gradle.kts
// Create extension object
interface GreetingPluginExtension {
    val message: Property<String>
}

// Add the 'greeting' extension object to project
val extension = project.extensions.create<GreetingPluginExtension>("greeting")

// Set a default value for 'message'
extension.message.convention("Hello from Gradle")
buildSrc/src/main/groovy/greetings.gradle
// Create extension object
interface GreetingPluginExtension {
    Property<String> getMessage()
}

// Add the 'greeting' extension object to project
def extension = project.extensions.create("greeting", GreetingPluginExtension)

// Set a default value for 'message'
extension.message.convention("Hello from Gradle")

extension.message.convention(…​) 为扩展的 message 属性设置了一个约定。此约定指定 message 的值应默认为 "Hello from Gradle"

如果未显式设置 message 属性,其值将自动设置为 "Hello from Gradle"

将扩展属性映射到 Task 属性

在插件中,使用扩展并将其映射到自定义 Task 的输入/输出属性是很常见的做法。

在此示例中,GreetingPluginExtension 的 message 属性被映射到 GreetingTask 的 message 属性作为输入

buildSrc/src/main/kotlin/greetings.gradle.kts
// Create extension object
interface GreetingPluginExtension {
    val message: Property<String>
}

// Add the 'greeting' extension object to project
val extension = project.extensions.create<GreetingPluginExtension>("greeting")

// Set a default value for 'message'
extension.message.convention("Hello from Gradle")

// Create a greeting task
abstract class GreetingTask : DefaultTask() {
    @Input
    val message = project.objects.property<String>()

    @TaskAction
    fun greet() {
        println("Message: ${message.get()}")
    }
}

// Register the task and set the convention
tasks.register<GreetingTask>("hello") {
    message.convention(extension.message)
}
buildSrc/src/main/groovy/greetings.gradle
// Create extension object
interface GreetingPluginExtension {
    Property<String> getMessage()
}

// Add the 'greeting' extension object to project
def extension = project.extensions.create("greeting", GreetingPluginExtension)

// Set a default value for 'message'
extension.message.convention("Hello from Gradle")

// Create a greeting task
abstract class GreetingTask extends DefaultTask {
    @Input
    abstract Property<String> getMessage()

    @TaskAction
    void greet() {
        println("Message: ${message.get()}")
    }
}

// Register the task and set the convention
tasks.register("hello", GreetingTask) {
    message.convention(extension.message)
}
$ gradle -q hello
Message: Hello from Gradle

这意味着对扩展的 message 属性的更改将触发 Task 被视为过时,从而确保 Task 使用新消息重新执行。

您可以在 延迟配置 中找到有关可在 Task 实现和扩展中使用的更多类型信息。

应用外部插件

要在预编译脚本插件中应用外部插件,必须将其添加到插件项目构建文件中的实现类路径中

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.bmuschko:gradle-docker-plugin:6.4.0")
}
buildSrc/build.gradle
plugins {
    id 'groovy-gradle-plugin'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.bmuschko:gradle-docker-plugin:6.4.0'
}

然后可以在预编译脚本插件中应用它

buildSrc/src/main/kotlin/my-plugin.gradle.kts
plugins {
    id("com.bmuschko.docker-remote-api")
}
buildSrc/src/main/groovy/my-plugin.gradle
plugins {
    id 'com.bmuschko.docker-remote-api'
}

在这种情况下,插件版本在依赖声明中定义。