如果 Gradle 或 Gradle 社区没有提供您的项目所需的特定功能,创建您自己的插件可能是一个解决方案。

此外,如果您发现自己在子项目中重复构建逻辑,并且需要更好的方式来组织它,自定义插件可以提供帮助。

自定义插件

插件是实现该Plugin接口的任何类。下面的例子是最简单的插件,一个“hello world”插件

构建.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!")
        }
    }
}

脚本插件

许多插件都是以构建脚本中编码的脚本插件开始的。这提供了一种在构建插件时快速原型化和实验的简单方法。让我们看一个例子:

构建.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 会调用fun apply() {}自定义类中定义的方法MyPlugin

这使得该插件可供应用程序使用。

不推荐使用脚本插件。脚本插件提供了一种快速原型构建逻辑的简单方法,然后将其迁移到更永久的解决方案(例如约定插件二进制插件)

约定插件

约定插件是一种在 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")
        }
    }
}

可以给插件一个idusinggradlePlugin{}块,以便可以在根中引用它:

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

gradlePlugin{}块定义了项目正在构建的插件。使用新创建的id,该插件可以相应地应用到其他构建脚本中:

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

二进制插件

二进制插件是用编译语言实现并打包为 JAR 文件的插件。它被解析为依赖项,而不是从源代码编译。

对于大多数用例,约定插件必须不经常更新。让每个开发人员在开发过程中执行插件构建是浪费的,我们可以将它们作为二进制依赖项分发。

有两种方法可以将上例中的约定插件更新为二进制插件。

  1. 使用复合构建

    设置.gradle.kts
    includeBuild("my-plugin")
  2. 将插件发布到存储库:

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

请参阅“开发插件”一章以了解更多信息。