如果 Gradle 或 Gradle 社区没有提供项目所需的特定功能,那么创建自己的插件可能是一种解决方案。
此外,如果你发现自己在子项目中重复构建逻辑,并且需要一种更好的方法来组织它,那么自定义插件可以提供帮助。
自定义插件
插件是实现 Plugin
接口的任何类。以下示例是最简单的插件,一个“hello world”插件
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!")
}
}
}
脚本插件
许多插件都是以构建脚本中编码的脚本插件开始的。这提供了一种在构建插件时快速制作原型和进行试验的简单方法。我们来看一个示例
// 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
中的约定插件
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
,以便可以在根目录中引用它
gradlePlugin {
plugins {
create("my-convention-plugin") {
id = "com.gradle.plugin.my-convention-plugin"
implementationClass = "com.gradle.plugin.MyConventionPlugin"
}
}
}
gradlePlugin{}
块定义了项目正在构建的插件。使用新创建的 id
,可以相应地在其他构建脚本中应用该插件
plugins {
application
id("com.gradle.plugin.my-convention-plugin") // Apply the new plugin
}