总体来说思路和自定义任务很类似,也是三种方式
概述
创建一个Gradle插件,需要编写一个实现Plugin接口的类。当插件被应用到一个项目时,Gradle创建了一个插件类的实例,并调用了实例的plugin.apply(T)方法。项目对象作为一个参数传递,插件可以使用它来配置项目,但是它需要这样做。
直接写在构建文件中
简单插件
下面的示例包含一个问候插件,它向项目中添加了一个hello任务
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// Apply the plugin
apply plugin: GreetingPlugin
c:\>gradle -q hello
Hello from the GreetingPlugin
c:\>
每一个自定义的Plugin都需要实现Plugin<T>接口,事实上,除了给Project编写Plugin之外,我们还可以为其他Gradle类编写Plugin。该接口定义了一个apply()方法,在该方法中,我们可以操作Project,比如向其中加入Task,定义额外的Property等。
需要注意的一点是,为每个应用程序创建一个插件的新实例。还请注意,Plugin的类是一种通用类型。这个例子将它作为一个类型参数接收到项目类型。插件可以接收类型设置的参数,在这种情况下,插件可以应用到设置脚本中,或者是一个类型Gradle的参数,在这种情况下,插件可以应用到一个初始化脚本中。
可配置插件
多数插件需要从构建脚本获得一些配置。这样做的一种方法是使用扩展对象。Gradle项目有一个相关的ExtensionContainer对象,该对象包含已应用到该项目的插件的所有设置和属性。您可以通过向这个容器添加一个扩展对象来为您的插件提供配置。扩展对象仅仅是一个符合Java Bean的类。Groovy是实现扩展对象的良好语言选择,因为普通的老Groovy对象包含Java Bean的所有getter和setter方法
class GreetingPluginExtension {
String message = '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
}
}
}
}
apply plugin: GreetingPlugin
// Configure the extension
greeting.message = 'Hi from Gradle'
c:\>gradle -q hello
Hi from Gradle
c:\>
在这个例子中,GreetingPluginExtension是一个普通的Groovy对象,具有一个名为message的属性。扩展对象被添加到插件列表中,并带有名称的问候。然后,这个对象就成为了一个具有与扩展对象同名的项目属性。
通常,您需要在一个插件上指定几个相关的属性。Gradle为每个扩展对象添加了一个配置闭包,所以你可以把设置组合在一起。下面的例子向您展示了它是如何工作的。
class GreetingPluginExtension {
String message
String greeter
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('greeting', GreetingPluginExtension)
project.task('hello') {
doLast {
println "${extension.message} from ${extension.greeter}"
}
}
}
}
apply plugin: GreetingPlugin
// Configure the extension using a DSL block
greeting {
message = 'Hi'
greeter = 'Gradle'
}
c:\>gradle -q hello
Hi from Gradle
c:\>
处理定制任务和插件中的文件
在开发定制任务和插件时,在接受文件位置的输入配置时,要非常灵活。要做到这一点,您可以利用project.file(java.lang.object)方法来尽可能晚地解析文件的值。
class GreetingToFileTask extends DefaultTask {
def destination
File getDestination() {
project.file(destination)
}
@TaskAction
def greet() {
def file = getDestination()
file.parentFile.mkdirs()
file.write 'Hello!'
}
}
task greet(type: GreetingToFileTask) {
destination = { project.greetingFile }
}
task sayGreeting(dependsOn: greet) {
doLast {
println file(greetingFile).text
}
}
ext.greetingFile = "$buildDir/hello.txt"
c:\>gradle -q sayGreeting
Hello!
c:\>
在这个例子中,我们将问候任务目的地属性配置为一个闭包,用project.File(java.lang.object)方法来评估,在最后一分钟将闭包的返回值转换为File对象。您会注意到,在上面的例子中,我们指定了greetingFile属性值,在我们配置了它用于任务之后。这种延迟的评估是在设置文件属性时接受任何值的一个关键好处,然后在读取属性时解析该值。
将扩展属性映射到任务属性
通过扩展将用户输入从构建脚本中捕获,并将其映射到定制任务的输入/输出属性,这被认为是最佳实践。最终用户只与扩展定义的公开DSL进行交互。必须的逻辑隐藏在插件实现中。
构建脚本中的扩展声明以及扩展属性和自定义任务属性之间的映射发生在构建生命周期的Gradle的配置阶段。为了避免评估顺序问题,映射属性的实际值必须在执行pha期间解决
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('greeting', GreetingPluginExtension, project)
project.tasks.create('hello', Greeting) {
message = extension.message
outputFiles = extension.outputFiles
}
}
}
class GreetingPluginExtension {
final Property<String> message
final ConfigurableFileCollection outputFiles
GreetingPluginExtension(Project project) {
message = project.objects.property(String)
message.set('Hello from GreetingPlugin')
outputFiles = project.files()
}
void setOutputFiles(FileCollection outputFiles) {
this.outputFiles.setFrom(outputFiles)
}
}
class Greeting extends DefaultTask {
final Property<String> message = project.objects.property(String)
final ConfigurableFileCollection outputFiles = project.files()
void setOutputFiles(FileCollection outputFiles) {
this.outputFiles.setFrom(outputFiles)
}
@TaskAction
void printMessage() {
outputFiles.each {
logger.quiet "Writing message 'Hi from Gradle' to file"
it.text = message.get()
}
}
}
apply plugin: GreetingPlugin
greeting {
message = 'Hi from Gradle'
outputFiles = files('a.txt', 'b.txt')
}
c:\>gradle -q hello
Writing message 'Hi from Gradle' to file
Writing message 'Hi from Gradle' to file
c:\>
在当前工程中定义Plugin
在当前工程中的目录下创建GreetingPlugin.groovy文件,将build.gradle中定义GreetingPlugin的代码提取到给文件中,但是除去对GreetingPluginExtension的定义,因为我们将在另外一个单独的文件中定义GreetingPluginExtension。
GreetingPlugin.groovy
package gradlePluginDemo.groovy
import org.gradle.api.Plugin
import org.gradle.api.Project
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("greeting", GreetingPluginExtension)
project.task('hello') << {
println "hello~~ "+project.demoProperties.message
}
}
}
GreetingPluginExtension.groovy:
package gradlePluginDemo.groovy
class GreetingPluginExtension {
message="xxxxxxx"
}
引用
apply plugin: gradlePluginDemo.groovy.GreetingPlugin
demoProperties{
message="yyyy"
}
执行“gradle greeting”
独立的项目
类似自定义任务,在项目的基础之上,加入导出和引用,可以参考自定义任务
buildscript {
repositories {
maven {
url uri('../repo')
}
}
dependencies {
classpath group: 'org.gradle', name: 'customPlugin',
version: '1.0-SNAPSHOT'
}
}
apply plugin: 'org.samples.greeting'