Gradle 插件

Gradle 的核心为真实世界提供了很少的自动化. 所有的实用特性,类似编译java源码的能力, 是由插件提供的. 插件添加了新的任务(如:JavaCompile),域对象(如:SourceSet),公约(如:Java资源位置是src/main/java)以及来自其他插件延伸核心对象和对象。

在本章中,我们将讨论如何使用插件和关于插件的周边概念和术语。

插件的作用是什么

应用插件到项目允许插件来扩展项目的能力。它可以做的事情,如:

  • 扩展摇篮模型(如:添加可配置新的DSL元素)
  • 按照惯例配置项目(如:添加新的任务或配置合理的默认值)
  • 应用特定的配置(如:增加组织库或执行标准)

通过应用插件,而不是向项目构建脚本添加逻辑,我们可以收获很多好处.应用插件:

  • 促进重用和减少维护在多个项目类似的逻辑的开销
  • 允许更高程度的模块化,提高综合性和组织
  • 封装必要的逻辑,并允许构建脚本尽可能是声明性地

插件的类型

在Gradle中一般有两种类型的插件,脚本插件和二进制插件.脚本插件是额外的构建脚本,它会进一步配置构建,通常实行声明的方式操纵的构建.尽管他们可以外部化并且从远程位置访问,它们通常还是会在构建内部中使用.二进制插件是实现了Plugin接口的类,并且采用编程的方式来操纵构建.二进制插件可以驻留在构建脚本,项目层级内或外部的插件jar.

应用插件

插件需要声明被应用,通过[Project.apply()](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:apply(java.util.Map)方法完成.应用的插件是idempotent注1,即相同的插件可以应用多次.如果插件先前以被应用,任何后来的应用是安全的,不会有任何影响的.

[1]译注:英文直接翻译的意思是幂等(denoting an element of a set that is unchanged in value when multiplied or otherwise operated on by itself.),上下中的大意应该是不会受其他因素的影响.

脚本插件

Example 21.1. Applying a script plugin

build.gradle

apply from: 'other.gradle'

脚本插件可以从本地文件系统或在远程位置的脚本中应用.文件系统的位置是相对于项目目录,而远程脚本位置的是由一个HTTP URL指定的.多个脚本插件(两种形式之一)可以被应用到给定的构建。

二进制插件

Example 21.2. Applying a binary plugin

build.gradle

apply plugin: 'java'

插件可以使用插件ID应用.插件的id作为给定的插件的唯一标识符.核心插件注册一个可以用作插件的id的短名称.在上述情况下,我们可以使用简称java的插件以应用JavaPlugin.社区插件,一方面会使用一个完全合格的形式的插件id(如com.github.foo.bar),但还是有一些传统的插件可能仍然使用很短的,不合格的格式.

不使用一个插件的id,插件也可以通过简单地指定类来应用插件:

Example 21.3. Applying a binary plugin by type

build.gradle

apply plugin: JavaPlugin

在上面的例子中,JavaPlugin是指JavaPlugin,此类不是严格需要导入org.gradle.api.plugins包中的所有自动导入构建脚本(见:附录E,现有的IDE支持,以及如何没有它应付).此外,这是没有必要追加的.class以识别一个类常量在Groovy,因为它是在Java中。

二进制插件的位置

一个插件是一个简单的实现了插件接口的类.Gradle提供的核心插件作为其分布的一部分,因此,你需要做的仅仅是应用上述的插件.然而,非核心二进制插件需要到构建类路径才能应用它们.这可以以多种方式,包括以下方式实现:

欲了解有关自定义插件的跟多信息,参见Chapter 61, Writing Custom Plugins

使用构建脚本块应用插件

项目可以通过添加向构建脚本中加入插件的类路径然后在应用插件,添加作为外部JAR文件的二进制插件.外部jar可以使用buildscrip{}块添加到构建脚本类路径就像Section 62.6, “External dependencies for the build script”中描述的一样.

Example 21.4. Applying a plugin with the buildscript block

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
    }
}

apply plugin: "com.jfrog.bintray"

使用插件的插件DSL

插件DSL正在孵化(incubating)中,请注意,在以后的Gradle版本中,DSL和其它配置可能会改变.

新的插件DSL提供了更为简洁,方便的方式来声明插件的依赖关系。它的适用于与新的Gradle Plugin Portal,同时提供了方便的核心和社区插件.该插件脚本块配置PluginDependenciesSpec的实例.

要应用的核心插件,可以使用短名称:

Example 21.5. Applying a core plugin

build.gradle

plugins {
    id 'java'
}

要从插件门户应用一个社区插件,必须使用插件的完全限定id:

Example 21.6. Applying a community plugin

build.gradle

plugins {
    id "com.jfrog.bintray" version "0.4.1"
}

不必要进行进一步的配置,就是说没有必要配置buildscript的类路径,Gradle会从插件门户找到该插件,并使构建可用.

参见PluginDependenciesSpec查看关于使用插件DSL的更多信息。

插件DSL的限制

想项目中添加插件的新方法不仅仅是一种更为方便的语法.新的DSL语法处理与老方法有很大的不同.新的机制允许Gradle更早更快的确定插件.这允许做更智能的事,如:

  • 优化插件类的加载和重用.
  • 允许不同的插件使用不同版本的依赖关系.
  • 为编辑构建脚本提供关于隐含属性和值的详细信息

这要求插件被指定使Gradle在执行之前剩下的构建脚本前可以很容易并且很快的提取它.还要求插件使用一些静态的定义。

新的插件机制与"传统的"apply()方法有一些关键区别.也有一些限制,其中一些限制是临时的,随着机制的成熟会逐渐没有,还有一些是方法固有的.

约束语法

新插件{}块不支持任意Groovy代码.被限制的原因是为幂等(每次产生相同的结果)和无副作用(为了Gradle随时执行的安全).

形式是:

plugins{
    id «plugin id»  version «plugin version»
}

«plugin id»«plugin version»必须是常量,字面量,字符串.其他语句都是不允许的;他们的存在会导致编译错误.

插件{}块也必须在构建脚本的顶部声明.它不能被嵌套在另一个结构(例如,if语句或for循环).

只能在构建脚本中使用

插件{}块目前只能在一个项目的构建脚本中使用.他不能在脚本插件,settings.gradle和出书画脚本中使用.

Gradle的未来版本将删除此限制.

不能与subjects{},allprojects{}等结合使用

目前不能使用一次添加一个插件到多个项目中的模式,如使用subprojects{}等方式.目前没有机制可以应用一次插件到多个项目.目前,每个项目都必须在自己的构建脚本中的plugins{}块中声明应用的插件.

Gradle的未来版本将删除此限制.

如果新语法的限制让人望而却步,推荐使用buildscript{} block.

查找社区插件

Gradle有一个充满活力的,卡法人员做出不用贡献的插件社区.该Gradle插件门户提供搜索和探索社区插件的接口.

更多关于插件

本章旨在作为介绍插件和Gradle,以及他们扮演的角色.要了解更过关于插件内部的工作原理,参见Chapter 61, Writing Custom Plugins.