预编译脚本插件通常是已编译并作为打包在库中的 Java 类文件分发的 Kotlin 脚本。这些脚本旨在用作二进制 Gradle 插件,建议用作约定插件。

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

设置插件 ID

预编译脚本的插件 ID 根据其文件名和可选包声明派生而来。

例如,一个名为 code-quality.gradle(.kts) 的脚本位于 src/main/groovy(或 src/main/kotlin)中,如果没有包声明,则会显示为 code-quality 插件

plugins {
    id("code-quality")
}

另一方面,一个名为 code-quality.gradle(.kts) 的脚本位于 src/main/groovy/my(或 src/main/kotlin/my)中,其中包含包声明 my,将显示为 my.code-quality 插件

plugins {
    id("my.code-quality")
}

使用文件

您应使用 Gradle 的托管属性。这将启用延迟配置,以便仅在需要文件时解析实际位置,并且可以在构建配置期间随时重新配置。

让我们通过创建一个名为 greetings 的约定插件来开始

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

您可以在使用文件中找到有关延迟使用文件的更多信息。

使用扩展使插件可配置

插件中通常使用扩展对象来向构建脚本公开配置选项和附加功能。

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

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的值应默认为位于项目构建目录中的名为defaultGreeting.txt的文件的内容。

如果未明确设置 message 属性,其值将自动设置为 defaultGreeting.txt 的内容。

将扩展属性映射到任务属性

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

在此示例中,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 属性进行更改将触发任务被视为过时,从而确保使用新消息重新执行任务。

您可以在 惰性配置 中找到有关可在任务实现和扩展中使用的类型的更多信息。

应用外部插件

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

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'
}

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