流程来自https://docs.gradle.org/current/userguide/custom_plugins.html
前置条件:Gradle7
要创建 Gradle 插件,需要编写一个实现 Plugin 接口的类。当插件应用于项目时,Gradle 会创建插件类的实例并调用实例的 Plugin.apply() 方法。创建的对象作为参数传递传递到gradle,插件可以根据需要使用它来配置项目。以下示例向项目添加了一个 hello 任务。
build.gradle
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// Apply the plugin
apply plugin: GreetingPlugin
输入gradle -q hello查看运行结果:
Hello from the GreetingPlugin
需要注意的一点是,一个Plugin的新实例是为每个应用它的项目创建的。另外,Plugin类是泛型类型,此示例将 Project 类型作为类型参数接收。插件可以改为接收 Settings 类型的参数,在这种情况下,插件可以在setting.gradle中应用,或者 Gradle 类型的参数,在这种情况下,插件可以在初始化脚本中应用
可配置插件
大多数插件为构建脚本和其他插件提供了一些配置选项,用于自定义插件的工作方式。插件使用扩展对象来做到这一点。 Gradle 项目有一个关联的 ExtensionContainer 对象,其中包含已应用于项目的插件的所有设置和属性。您可以通过向此容器添加扩展对象来为您的插件提供配置。扩展对象只是具有代表配置的 Java Bean 属性的对象。 让我们在项目中添加一个简单的扩展对象。在这里,我们向项目添加了一个问候扩展对象,它允许您配置问候语。
abstract class GreetingPluginExtension {
abstract Property<String> getMessage()
GreetingPluginExtension() {
message.convention('Hello from GreetingPlugin')
}
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// Add the 'greeting' extension object
def extension = project.extensions.create('greeting', GreetingPluginExtension)
// Add a task that uses configuration from the extension object
project.task('hello') {
doLast {
println extension.message.get()
}
}
}
}
apply plugin: GreetingPlugin
// Configure the extension
greeting.message = 'Hi from Gradle'
在这个例子种,GreetingPluginExtension拥有一个叫做message的变量,插件通过他的名字greeting添加到project中。然后,此对象可用作与扩展对象同名的项目属性。通常,您需要在单个插件上指定多个相关属性。 Gradle 为每个扩展对象添加了一个配置块,因此您可以将设置组合在一起。以下示例向您展示了它是如何工作的。
interface GreetingPluginExtension {
Property<String> getMessage()
Property<String> getGreeter()
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('greeting', GreetingPluginExtension)
project.task('hello') {
doLast {
println "${extension.message.get()} from ${extension.greeter.get()}"
}
}
}
}
apply plugin: GreetingPlugin
// Configure the extension using a DSL block
greeting {
message = 'Hi'
greeter = 'Gradle'
}
在这个例子中,几个设置可以在问候闭包中组合在一起。构建脚本(问候语)中的闭包块的名称需要与扩展对象名称相匹配。然后,当闭包执行时,扩展对象上的字段将根据标准的 Groovy 闭包委托特性映射到闭包内的变量。 这样,使用扩展对象扩展 Gradle DSL 来为插件添加项目属性和 DSL 块。由于扩展对象只是一个常规对象,因此您可以通过向扩展对象添加属性和方法来提供嵌套在插件块内的自己的 DSL
开发项目扩展
You can find out more about implementing project extensions in Developing Custom Gradle Types.
Working with files in custom tasks and plugins
在开发自定义任务和插件的时候,推荐使用文件作为配置项。你可以使用Gradle的托管属性和project.layout去选择文件或者文件夹。通过这种方式,只有在真正使用这个文件的时候才会访问定义的路径,所以可以在任何时候配置文件。
abstract class GreetingToFileTask extends DefaultTask {
@OutputFile
abstract RegularFileProperty getDestination()
@TaskAction
def greet() {
def file = getDestination().get().asFile
file.parentFile.mkdirs()
file.write 'Hello!'
}
}
def greetingFile = objects.fileProperty()
tasks.register('greet', GreetingToFileTask) {
destination = greetingFile
}
tasks.register('sayGreeting') {
dependsOn greet
doLast {
def file = greetingFile.get().asFile
println "${file.text} (file: ${file.name})"
}
}
greetingFile.set(layout.buildDirectory.file('hello.txt'))
在这个例子中,我们将 greet 任务destination配置为一个闭包/提供者,使用 Project.file(java.lang.Object) 方法来赋值,最后将闭包/提供者的返回值转换为 File 对象。您会注意到,在上面的示例中,我们在配置为将它用于任务之后指定了 greetingFile 属性值。这种惰性求值的主要好处是在设置文件属性时接受任何值,然后在读取属性时解析该值。
将扩展属性映射到任务属性
通过扩展从构建脚本中捕获用户输入并将其映射到自定义任务的输入/输出属性是一种有用的模式。构建脚本作者仅与扩展定义的 DSL 交互。命令式逻辑隐藏在插件实现中。