Writing Custom Gradle Plugins – 编写自定义Gradle插件

最后修改: 2017年 12月 4日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Gradle is a very popular build tool, which is often appreciated for the highly-customizable build process.

Gradle是一个非常流行的构建工具,它经常因为高度可定制的构建过程而受到赞赏。

Today we’re going to show how to create custom Gradle plugins, that will allow us to modify the build process beyond what we can achieve with the standard configuration.

今天我们将展示如何创建自定义的Gradle插件,这将使我们能够修改构建过程,使其超出标准配置所能实现的范围。

2. Plugin Source Location

2.插件源的位置

We can place our code in a few different locations. All of them have some advantages and disadvantages.

我们可以将我们的代码放在几个不同的位置。所有这些都有一些优点和缺点。

2.1. Build Script

2.1.构建脚本

We can simply put the source code of our plugin inside the build script itself. This will give us automatic compilation and inclusion of the plugin.

我们可以简单地把我们的插件的源代码放在构建脚本本身里面。这将给我们带来自动编译和包含该插件的机会。

It’s very simple, however, our plugin won’t be visible outside of the build script. Because of that, we can’t reuse it in other build scripts.

这非常简单,但是,我们的插件在构建脚本之外是不可见的。正因为如此,我们不能在其他构建脚本中重复使用它。

2.2. BuildSrc Folder

2.2.BuildSrc 文件夹

Another possibility that we can use is placing the source code of our plugin in the buildSrc/src/main/java folder.

我们可以使用的另一种可能性是将我们的插件的源代码放在buildSrc/src/main/java文件夹中。

When you run Gradle, it’ll check for the existence of the buildSrc folder. If that exists, Gradle will automatically build and include our plugin.

当你运行Gradle时,它会检查buildSrc文件夹的存在。如果它存在,Gradle就会自动构建并包含我们的插件。

This will give us the possibility to share our plugin between various build scripts, but we still won’t be able to use it in other projects.

这将使我们有可能在各种构建脚本之间共享我们的插件,但我们仍然无法在其他项目中使用它。

2.3. Standalone Project

2.3.独立的项目

Finally, we can create our plugin as a separate project which makes the plugin fully reusable in various projects.

最后,我们可以将我们的插件创建为一个独立的项目,这使得该插件在不同的项目中完全可以重复使用。

However, to use it in an external project, we’ll need to bundle it in a jar file and add to a project.

然而,要在一个外部项目中使用它,我们需要将它捆绑在一个jar文件中,然后添加到一个项目中。

3. Our First Plugin

3.我们的第一个插件

Let’s start with the basics – every Gradle Plugin must implement the com.gradle.api.Plugin interface.

让我们从基础开始 – 每个Gradle插件都必须实现com.gradle.api.Plugin接口

The interface is generic, so we can parametrize it with various parameter types. Usually, the parameter type is org.gradle.api.Project.

这个接口是通用的,所以我们可以用各种参数类型对它进行参数化。通常情况下,参数类型是org.gradle.api.Project.

However, we can use different type parameters so that the plugin is applied in different lifetime phases:

然而,我们可以使用不同的类型参数,以便在不同的生命周期阶段应用该插件。

  • using org.gradle.api.Settings will result in applying the plugin to a settings script
  • using org.gradle.api.Gradle will result in applying the plugin to an initialization script

The simplest plugin we can create is a hello world application:

我们可以创建的最简单的插件是一个hello world应用程序。

public class GreetingPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        project.task("hello")
          .doLast(task -> System.out.println("Hello Gradle!"));
    }
}

We can now apply it by adding a line inside our build script:

现在我们可以通过在我们的构建脚本中添加一行来应用它。

apply plugin: GreetingPlugin

Now, after calling gradle hello, we’ll see “Hello Gradle” message in logs.

现在,在调用gradle hello之后,我们会在日志中看到“Hello Gradle” 消息。

4. Plugin Configuration

4.插件配置

Most plugins will need an access to an external configuration from the build script.

大多数插件将需要从构建脚本中访问外部配置。

We can do that by using extension objects:

我们可以通过使用扩展对象来做到这一点。

public class GreetingPluginExtension {
    private String greeter = "Baeldung";
    private String message = "Message from the plugin!"
    // standard getters and setters
}

Let’s now add the new extension object to our plugin class:

现在让我们把新的扩展对象添加到我们的插件类。

@Override
public void apply(Project project) {
    GreetingPluginExtension extension = project.getExtensions()
      .create("greeting", GreetingPluginExtension.class);

    project.task("hello")
      .doLast(task -> {
          System.out.println(
            "Hello, " + extension.getGreeter());
          System.out.println(
            "I have a message for You: " + extension.getMessage());
      });
}

Now, when we call gradle hello, we’ll see the default message defined in our GreetingPluginExtension.

现在,当我们调用gradle hello时,我们将看到在我们的GreetingPluginExtension>中定义的默认消息。

But since we have created the extension, we can use a closure to do that inside the build script:

但由于我们已经创建了扩展,我们可以在构建脚本中使用一个闭包来做到这一点。

greeting {
    greeter = "Stranger"
    message = "Message from the build script" 
}

5. Standalone Plugin Project

5.独立的插件项目

For creating a standalone Gradle plugins, we need to do a little more work.

对于创建一个独立的Gradle插件,我们需要多做一些工作。

5.1. Setup

5.1.设置

Firstly, we need to import the Gradle API dependency – which is quite straightforward:

首先,我们需要导入Gradle API的依赖关系–这是很直接的。

dependencies {
    compile gradleApi()
}

Note that doing the same in Maven requires gradle-tooling-api dependency – from the Gradle repository:

注意,在Maven中做同样的事情需要gradle-tooling-api依赖–来自Gradle仓库。

<dependencies>
    <dependency>
        <groupId>org.gradle</groupId>
        <artifactId>gradle-tooling-api</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>org.gradle</groupId>
        <artifactId>gradle-core</artifactId>
        <version>3.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
<repositories>
    <repository>
        <id>repo.gradle.org</id>
        <url>https://repo.gradle.org/gradle/libs-releases-local/</url>
    </repository>
</repositories>

5.2. Wiring the Plugin

5.2.为插件布线

To allow Gradle to find the implementation of our standalone plugin, we need to create the properties file in the src/main/resources/META-INF/gradle-plugins.

为了让Gradle找到我们独立插件的实现,我们需要在src/main/resources/META-INF/gradle-plugins中创建属性文件。

The resource file needs to have a name that matches the plugin id. So if our plugin has an id of org.baeldung.greeting, the exact path of the file would be META-INF/gradle-plugins/org.baeldung.greeting.properties.

资源文件需要有一个与插件ID相匹配的名字。因此,如果我们的插件的id是org.baeldung.greeting,文件的确切路径将是META-INF/gradle-plugins/org.baeldung.greeting.properties。

Next, we can define the implementation class of the plugin:

接下来,我们可以定义该插件的实现类。

    implementation-class=org.gradle.GreetingPlugin

The implementation-class should be equal to the full package name of our plugin class.

implementation-class应该等于我们的插件类的完整包名。

5.3. Creating the Plugin ID

5.3.创建插件ID

There are some rules and conventions that plugin ID must follow in Gradle. Most of them are similar to package name rules in Java:

在Gradle中,有一些插件ID必须遵循的规则和惯例。它们中的大多数与Java中的包名规则相似。

  • They can contain only alphanumeric characters, “.” and “-“
  • The id has to have at least one “.” separating the domain name from the plugin name
  • Namespaces org.gradle and com.gradleware are restricted
  • An id cannot start or end with “.”
  • No two or more consecutive “.” characters are allowed

Finally, there’s a convention that plugin Id should be a lower case name that follows reverse domain name convention.

最后,有一个惯例,即插件Id应该是一个遵循反向域名惯例的小写名称。

The main difference between Java package names and Gradle plugin names is that the package name is usually more detailed than the plugin ID.

Java包名和Gradle插件名的主要区别是,包名通常比插件ID更详细。

5.4. Publishing Plugin

5.4.发布插件

When we want to publish our plugin to be able to reuse it in external projects, we have two ways of achieving that.

当我们想发布我们的插件,以便能够在外部项目中重用它时,我们有两种方法来实现。

Firstly, we can publish our plugin JAR to an external repository like Maven or Ivy.

首先,我们可以将我们的插件JAR发布到一个外部仓库,如MavenIvy.

Alternatively, we can use the Gradle Plugin Portal. This will allow our plugin to be accessible by wide Gradle Community. More on publishing projects to Gradle repository can be found in Gradle Plugin Portal Documentation.

另外,我们也可以使用Gradle插件门户。这将使我们的插件能够被广大的Gradle社区所访问。更多关于发布项目到Gradle仓库的信息可以在Gradle Plugin Portal文档中找到。

5.5. Java Gradle Development Plugin

5.5.Java的Gradle开发插件

When we’re writing our plugins in Java, we can benefit from the Java Gradle Development Plugin.

当我们用Java编写插件时,我们可以从Java Gradle开发插件中获益。

This will automatically compile and add gradleApi() dependencies. It will also perform plugin metadata validation as a part of the gradle jar task.

这将自动编译并添加gradleApi()依赖项。它还将执行插件元数据验证,作为gradle jar任务的一部分。

We can add plugin by adding following block to our build script:

我们可以通过在我们的构建脚本中添加以下块来添加插件。

plugins {
    id 'java-gradle-plugin'
}

6. Testing Plugins

6.测试插件

To test that our plugin works properly and it’s properly applied to the Project, we can use org.gradle.testfixtures.ProjectBuilder to create an instance of the Project.

为了测试我们的插件是否正常工作,并且正确地应用于Project,我们可以使用org.gradle.testfixtures.ProjectBuilder来创建一个Project的实例。

We can then check if the plugin was applied and proper tasks are present in our Project instance. We can use standard JUnit tests to do that:

然后我们可以检查该插件是否被应用,并且在我们的项目实例中存在适当的任务。我们可以使用标准的JUnit测试来做到这一点。

@Test
public void greetingTest(){
    Project project = ProjectBuilder.builder().build();
    project.getPluginManager().apply("com.baeldung.greeting");
 
    assertTrue(project.getPluginManager()
      .hasPlugin("com.baeldung.greeting"));
 
    assertNotNull(project.getTasks().getByName("hello"));
}

7. Summary

7.总结

In this article, we’ve shown the basics of writing custom plugins in Gradle. To go more in-depth into plugin creation, have a look at the Gradle Documentation.

在这篇文章中,我们已经展示了在Gradle中编写自定义插件的基本知识。要更深入地了解插件的创建,请看Gradle文档

And, as always, all the code samples can be found over on Github.

而且,像往常一样,所有的代码样本都可以在Github上找到over

Next »

Creating a Fat Jar in Gradle

« Previous

Ant vs Maven vs Gradle