Gradle插件打包可重用的构建逻辑片段,可用于许多不同的项目和构建。 Gradle允许实现自己的插件,因此可以重用构建逻辑,并与其他人共享。
可以使用任何语言实现Gradle插件,前提是实现最终编译为JVM字节码。 在我们的示例中,我们将使用Groovy作为实现语言。 Groovy,Java或Kotlin都是用于实现插件的语言的不错选择,因为Gradle API旨在与这些语言一起使用。 通常,使用Java或Kotlin实现的静态类型的插件将比使用Groovy实现的相同插件执行得更好。
有几个地方可以放置插件的源代码。
可以直接在构建脚本中包含插件的源代码。这样做的好处是插件可以自动编译并包含在构建脚本的类路径中,而无需执行任何操作。但是,插件在构建脚本之外是不可见的,因此您无法在其定义的构建脚本之外重用该插件。
可以将插件的源代码放在rootProjectDir / buildSrc / src / main / groovy目录(或rootProjectDir / buildSrc / src / main / java或rootProjectDir / buildSrc / src / main / kotlin中。)Gradle将负责编译和测试插件并使其在构建脚本的类路径中可用。 该插件对于构建使用的每个构建脚本都是可见的。 但是,它在构建之外是不可见的,因此您无法在其定义的构建之外重用该插件。
可以为插件创建单独的项目。 该项目生成并发布一个JAR,然后您可以在多个版本中使用它并与其他人共享。 通常,此JAR可能包含一些插件,或将多个相关的任务类捆绑到单个库中。 或两者的某种组合。
要创建Gradle插件,需要编写一个实现Plugin接口的类。 当插件应用于项目时,Gradle会创建插件类的实例并调用实例的Plugin.apply()方法。 项目对象作为参数传递,插件可以使用它来配置项目。
## 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类是泛型类型。 此示例使其接收Project类型作为类型参数。 插件可以改为接收类型为Settings的参数,在这种情况下,插件可以应用于设置脚本或Gradle类型的参数,在这种情况下,插件可以应用于初始化脚本中。
大多数插件需要从构建脚本中获取一些配置。执行此操作的一种方法是使用扩展对象。Gradle项目具有关联的ExtensionContainer对象,该对象包含已应用于项目的插件的所有设置和属性。可以通过向此容器添加扩展对象来为插件提供配置。扩展对象只是一个Java Bean兼容类。
##build.gradle 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' 复制代码
> gradle -q hello Hi from Gradle 复制代码
在此示例中,GreetingPluginExtension是一个普通的Groovy / Kotlin对象,其中包含一个名为message的属性。 扩展对象将添加到名称为greeting的插件列表中。 然后,此对象可用作与扩展对象同名的项目属性。
通常,您需要在单个插件上指定几个相关属性。 Gradle为每个扩展对象添加配置块,因此您可以将设置组合在一起。
##build.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' } 复制代码
> gradle -q hello Hi from Gradle 复制代码
在此示例中,可以在greeting闭包内将多个设置组合在一起。 构建脚本(greeting)中闭包块的名称需要与扩展对象名称匹配。 然后,当执行闭包时,扩展对象上的字段将根据标准Groovy闭包委托功能映射到闭包内的变量。
在开发自定义任务和插件时,最好在接受文件位置的输入配置时保持灵活性。 为此,您可以利用Project.file(java.lang.Object)方法尽可能晚地将值解析为文件。
## build.gradle 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" 复制代码
> gradle -q sayGreeting Hello! 复制代码
在此示例中,我们将greet任务的destination属性配置为闭包/提供程序,使用Project.file(java.lang.Object)方法对其进行评估,以将闭包/提供程序的返回值转换为最后的File对象。在上面的示例中,我们在配置为将其用于任务后指定greetingFile属性值。 这种延迟评估是在设置文件属性时接受任何值,然后在读取属性时解析该值的关键优势。
通过扩展从构建脚本捕获用户输入并将其映射到自定义任务的输入/输出属性是一种有用的模式。 构建脚本作者仅与扩展名定义的DSL进行交互。 命令式逻辑隐藏在插件实现中。
Gradle提供了一些可以在任务实现和扩展中使用的类型来帮助您完成此任务。
现在我们将把我们的插件移到一个独立的项目中,这样我们就可以发布它并与其他人共享。 这个项目只是一个Groovy项目,它生成一个包含插件类的JAR。 这是项目的简单构建脚本。 它应用Groovy插件,并将Gradle API添加为编译时依赖项。
##build.gradle plugins { id 'groovy' } dependencies { implementation gradleApi() implementation localGroovy() } 复制代码
那么Gradle如何找到插件实现呢? 答案是你需要在jar的META-INF / gradle-plugins目录中提供一个与你的插件的id匹配的属性文件。
src/main/resources/META-INF/gradle-plugins/org.samples.greeting.properties
implementation-class=org.gradle.GreetingPlugin 复制代码
请注意,属性文件名与插件ID匹配,并且放在resources文件夹中,而implementation-class属性标识插件实现类。
插件ID以类似于Java包的方式(即反向域名)完全限定。 这有助于避免冲突,并提供了一种对具有类似所有权的插件进行分组的方法。
插件ID应该是反映命名空间(指向您或您的组织的合理指针)的组件的组合,以及它提供的插件的名称。例如,如果您有一个名为“foo”的Github帐户,并且您的插件名为“bar”,则合适的插件ID可能是com.github.foo.bar。
## java-publish.gradle apply plugin: 'maven-publish' def javadocJar = task("javadocJar", type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } def sourcesJar = task("sourcesJar", type: Jar) { classifier = 'sources' from sourceSets.main.java.srcDirs } publishing { publications { Component(MavenPublication) { from components.java groupId = group artifactId = POM_ARTIFACT_ID version = version artifact sourcesJar artifact javadocJar } } } task buildAndPublishToLocalMaven(type: Copy, dependsOn: ['build', 'publishToMavenLocal']) { group = POM_NAME // save artifacts files to artifacts folder from configurations.archives.allArtifacts.files into "${rootProject.buildDir}/outputs/artifacts/" rename { String fileName -> fileName.replace("release.aar", "${version}.aar") } doLast { println "* published to maven local: ${project.group}:${project.name}:${project.version}" } } 复制代码
## gradle.properties POM_ARTIFACT_ID=greeting-gradle-plugin POM_NAME=greeting POM_PACKAGING=jar 复制代码
点击之后会在本地仓库生成对应的jar包:
找到项目的根目录的build.gradle文件:
buildscript { repositories { mavenLocal() google() jcenter() } dependencies { // classpath classpath 'com.android.tools.build:gradle:3.2.1' classpath("com.zpw.greeting:greeting-gradle-plugin:1.0") } } 复制代码
然后在项目app的build.gradle文件中添加:
apply plugin: 'com.zpw.greeting_plugin' 复制代码
可以使用扩展对象为插件提供配置。 使用扩展对象还扩展了Gradle DSL,为插件添加项目属性和DSL块。 扩展对象只是一个常规对象,因此您可以通过向扩展对象添加属性和方法来提供嵌套在此块中的DSL元素。
当Gradle创建任务或扩展对象时,Gradle会修改实现类以混合DSL支持和可扩展性。 要创建嵌套的DSL元素,可以使用ObjectFactory类型创建类似装饰的对象。 然后,可以通过插件扩展的属性和方法使这些装饰对象对DSL可见:
class GreetingPluginExtension { String message } 复制代码
class GreetingPlugin implements Plugin<Project> { @Override void apply(Project project) { def extension = project.extensions.create('greeting', GreetingPluginExtension) project.task('hello') { doLast { println "${extension.message}" } } } } 复制代码
apply plugin: 'com.zpw.greeting_plugin' greeting { message = 'Hi' } 复制代码
> gradle -q hello Hi 复制代码