Gradle 插件开发笔记01

[toc]

由于工作原因,需要进行 gradle 的插件开发,因此参考官方文档记录开发 gradle 插件的过程。

你可以使用 Java、Groovy、Kotlin 等语言来实现 Gradle 插件,前提是该实现最终被编译为 JVM 字节码。通常情况下使用静态类型的 Java 或 Kotlin 实现的插件比使用 Groovy 实现的插件性能更好。

这里主要记录在一个独立项目中进行插件的开发,方便开发完成后团队其它成员使用。

创建一个单独的插件

GreetingPlugin

  1. public class GreetingPlugin implements Plugin<Project> {
  2. private Project project;
  3. private TaskContainer taskContainer;
  4. @Override
  5. public void apply(Project target) {
  6. this.project = target;
  7. this.taskContainer = project.getTasks();
  8. createHelloTask();
  9. }
  10. private void createHelloTask() {
  11. project.afterEvaluate(new Action<Project>() {
  12. @Override
  13. public void execute(Project project) {
  14. TaskProvider<GreetingTask> hello = taskContainer.register("hello", GreetingTask.class);
  15. hello.get().dependsOn("test").setGroup(JavaBasePlugin.VERIFICATION_GROUP);
  16. }
  17. });
  18. }
  19. }

插件可配置化

大多数插件为构建脚本和其他插件提供了一些配置选项,用于自定义插件的工作方式。Gradle Project有一个关联的 ExtensionContainer 对象,其中包含已应用于项目的插件的所有设置和属性。你可以通过向此容器添加扩展对象来为你的插件提供配置。扩展对象只是一个具有代表配置的 Java Bean 属性的对象。

GreetingPluginExtension

  1. public abstract class GreetingPluginExtension {
  2. public abstract Property<String> getMessage();
  3. GreetingPluginExtension() {
  4. getMessage().convention("Hello from GreetingPlugin");
  5. }
  6. }

GreetingPlugin

  1. public class GreetingPlugin implements Plugin<Project> {
  2. private Project project;
  3. private TaskContainer taskContainer;
  4. @Override
  5. public void apply(Project target) {
  6. this.project = target;
  7. this.taskContainer = project.getTasks();
  8. createHelloTask();
  9. }
  10. private void createHelloTask() {
  11. GreetingPluginExtension greeting = project.getExtensions().create("greeting", GreetingPluginExtension.class);
  12. project.task("hello").doFirst(task -> System.out.println(greeting.getMessage().get()));
  13. }
  14. }

在此示例中,GreetingPluginExtension 是一个具有名为 message 的属性的对象。扩展对象被添加到项目中,名称为greeting。然后,此对象可用作与扩展对象同名的项目属性。

通常,您需要在单个插件上指定多个相关属性。 Gradle 为每个扩展对象添加了一个配置块,因此您可以将设置组合在一起。以下示例向您展示了这是如何工作的。

  1. interface GreetingPluginExtension {
  2. Property<String> getMessage()
  3. Property<String> getGreeter()
  4. }
  5. class GreetingPlugin implements Plugin<Project> {
  6. void apply(Project project) {
  7. def extension = project.extensions.create('greeting', GreetingPluginExtension)
  8. project.task('hello') {
  9. doLast {
  10. println "${extension.message.get()} from ${extension.greeter.get()}"
  11. }
  12. }
  13. }
  14. }
  15. apply plugin: GreetingPlugin
  16. // Configure the extension using a DSL block
  17. greeting {
  18. message = 'Hi'
  19. greeter = 'Gradle'
  20. }

在此示例中,可以在问候语闭包中将多个设置组合在一起。构建脚本(greeting)中的闭包块的名称需要与扩展对象名称相匹配。然后,当执行闭包时,扩展对象上的字段将根据标准 Groovy 闭包委托功能映射到闭包内的变量。

这样,使用扩展对象扩展了 Gradle DSL 来为插件添加项目属性和 DSL 块。并且因为扩展对象只是一个常规对象,您可以通过向扩展对象添加属性和方法来提供嵌套在插件块中的自己的 DSL

开发项目扩展

您可以在开发自定义 Gradle 类型中找到更多关于实现项目扩展的信息。

使用自定义任务和插件中的文件

在开发自定义任务和插件时,在接受文件位置的输入配置时非常灵活是一个好主意。您应该使用 Gradle 的托管属性和 project.layout 来选择文件或目录位置。这样,实际位置只会在需要文件时解析,并且可以在构建配置期间随时重新配置。

  1. abstract class GreetingToFileTask extends DefaultTask {
  2. @OutputFile
  3. abstract RegularFileProperty getDestination()
  4. @TaskAction
  5. def greet() {
  6. def file = getDestination().get().asFile
  7. file.parentFile.mkdirs()
  8. file.write 'Hello!'
  9. }
  10. }
  11. def greetingFile = objects.fileProperty()
  12. tasks.register('greet', GreetingToFileTask) {
  13. destination = greetingFile
  14. }
  15. tasks.register('sayGreeting') {
  16. dependsOn greet
  17. doLast {
  18. def file = greetingFile.get().asFile
  19. println "${file.text} (file: ${file.name})"
  20. }
  21. }
  22. greetingFile.set(layout.buildDirectory.file('hello.txt'))