Gradle的核心是有意为现实世界的自动化提供很少的东西。所有有用的特性,比如编译Java代码的能力,都是由插件添加的。插件添加新任务(如JavaCompile),域对象(如SourceSet),约定(如Java源位于src/main/ Java)以及扩展核心对象和来自其他插件的对象。
将插件应用到项目中可以使插件扩展项目的功能。它可以做以下事情:
扩展Gradle模型(例如,添加新的可以配置的DSL元素)
根据约定配置项目(例如添加新任务或配置合理的默认值)
应用特定的配置(例如,添加组织存储库或实施标准)
通过应用插件,而不是向项目构建脚本添加逻辑,我们可以获得许多好处。应用插件:
促进重用并减少跨多个项目维护相似逻辑的开销
允许更高程度的模块化,增强可理解性和组织性
封装命令式逻辑,并允许构建脚本尽可能具有声明性
在Gradle中有两种常见的插件,二进制插件和脚本插件。二进制插件可以通过实现Plugin接口以编程方式编写,也可以使用Gradle的DSL语言以声明方式编写。二进制插件可以驻留在构建脚本中、项目层次结构中或外部插件jar中。脚本插件是进一步配置构建的附加构建脚本,通常实现一种声明性的方法来操作构建。它们通常在构建中使用,尽管它们可以外部化并从远程位置访问。
一个插件通常一开始是一个脚本插件(因为它们很容易编写),然后,随着代码变得更有价值,它被迁移到一个二进制插件,可以很容易地测试和在多个项目或组织之间共享。
要使用封装在插件中的构建逻辑,Gradle需要执行两个步骤。
首先,它需要解析插件,然后需要将插件应用到目标,通常是一个项目。
解析一个插件意味着找到包含给定插件的jar的正确版本,并将其添加到脚本类路径中。一旦一个插件被解析,它的API就可以在构建脚本中使用。脚本插件是自解析的,因为它们是从应用它们时提供的特定文件路径或URL解析的。作为Gradle发行版的一部分提供的核心二进制插件是自动解析的。
应用插件意味着在你想要用插件增强的项目上实际执行插件的plugin. apply(T)。应用插件是幂等的。也就是说,你可以安全地多次应用任何插件而没有副作用。
使用插件最常见的用例是解析插件并将其应用到当前项目。由于这是一个非常常见的用例,因此建议构建作者使用插件DSL(Android Plugin DSL 就是 Google 为了开发 Android 应用定制了一个插件)在一个步骤中解析和应用插件。具体参考官方参考文档
通过插件id应用插件,这是插件的全局唯一标识符或名称。核心Gradle插件的特殊之处在于它们提供了简短的名称,例如核心的JavaPlugin是“java”。所有其他二进制插件必须使用插件id的完全限定形式(例如com.github.foo.bar),尽管一些遗留的插件可能仍然使用简短的、不限定的形式。你把插件id放在哪里取决于你是使用插件DSL还是buildscript块。
插件就是实现plugin接口的任何类。Gradle提供了核心插件(例如JavaPlugin)作为其发行版的一部分,这意味着它们是自动解析的。但是,非核心二进制插件在应用之前需要进行解析。这可以通过以下几种方式来实现:
使用plugins DSL从插件门户或自定义存储库中包含插件(请参阅使用plugins DSL应用插件)。
包括从外部jar定义为buildscript依赖的插件(参见使用buildscript块应用插件)。
将插件定义为项目中buildSrc目录下的源文件(参见使用buildSrc提取函数逻辑)。
将插件定义为构建脚本中的内联类声明。
有关定义自己的插件的更多信息,请参见自定义插件。
plugins DSL提供了一种简洁方便的方式来声明插件依赖关系。它与Gradle插件门户一起工作,提供对核心插件和社区插件的方便访问。插件DSL块配置一个PluginDependenciesSpec实例。
要应用核心插件,可以使用其短名称:
例1。应用核心插件
//build.gradle中添加
plugins {
id 'java'
}
要从门户应用社区插件,必须使用完全限定的插件id:
//build.gradle
plugins {
id 'com.jfrog.bintray' version '1.8.5'
}
这种向项目中添加插件的方式不仅仅是一种更方便的语法。插件DSL的处理方式允许Gradle在非常早和非常快的时候确定正在使用的插件。这使得Gradle可以做一些聪明的事情,比如:
优化插件类的加载和重用。
为编辑器提供有关构建脚本中潜在属性和值的详细信息,以帮助编辑。
这要求在执行其余的构建脚本之前,以Gradle可以轻松快速提取的方式指定插件。它还要求所使用的插件的定义在某种程度上是静态的。
在plugins{}块机制和“传统的”apply() 方法机制之间有一些关键的区别。还有一些限制,其中一些是机制仍在开发期间的临时限制,还有一些是新方法固有的。
plugins{}块 不支持任意代码。它是受约束的,为了幂等(每次产生相同的结果)和无副作用(安全的Gradle在任何时候执行)。
其形式是:
plugins {
//用于Gradle核心插件或构建脚本中已经可用的插件
id «plugin id»
//用于需要解析的二进制Gradle插件
id «plugin id» version «plugin version» [apply «false»]
}
当 «plugin id» 和 «plugin version» 必须为常量时,可以使用文字、字符串和带有布尔值的apply语句来禁用立即应用插件的默认行为(例如,您只想在子项目中应用它)。不允许使用其他语句,否则将导致编译错误。
如果要使用变量定义插件版本,下文中会介绍。
plugins{} 块也必须是buildscript中的顶级语句。它不能嵌套在另一个结构中(例如if-statement或for-loop)。
plugins{}块目前只能在项目的构建脚本和settings.gradle文件中使用。不能在脚本插件或初始化脚本中使用。将来的Gradle版本将会移除这个限制。如果plugins{} 块的限制是禁止的,推荐的方法是使用buildscript{} 块应用插件。
如下示例:
//build.gradle
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
apply plugin: 'com.jfrog.bintray'
如果您有一个多项目构建,您可能希望将插件应用到构建中的部分或所有子项目,但不应用到根项目。plugins{}块的默认行为是立即解析和应用插件。但是,你可以使用apply false语法告诉Gradle不要将插件应用到当前项目,然后在子项目的构建脚本中使用plugins{}块,而不使用版本:
如下示例:只在特定子项目上应用插件
//settings.gradle
include 'hello-a'
include 'hello-b'
include 'goodbye-c'
//build.gradle
plugins {
id 'com.example.hello' version '1.0.0' apply false
id 'com.example.goodbye' version '1.0.0' apply false
}
// hello-a/build.gradle
plugins {
id 'com.example.hello'
}
//hello-b/build.gradle
plugins {
id 'com.example.hello'
}
//goodbye-c/build.gradle
plugins {
id 'com.example.goodbye'
}
更好的是——你可以通过使用自己的约定插件组合构建逻辑来封装外部插件的版本。
您可以应用驻留在项目的buildSrc目录中的插件,只要它们具有定义的ID。下面的例子展示了如何绑定一个插件实现类my.MyPlugin -在buildSrc中定义为ID “my-plugin”:
示例:定义带有ID的buildSrc插件
//buildSrc/build.gradle
plugins {
id 'java-gradle-plugin'
}
gradlePlugin {
plugins {
myPlugins {
id = 'my-plugin'
implementationClass = 'my.MyPlugin'
}
}
}
应用插件:插件可以按ID正常应用:
//build.gradle
plugins {
id 'my-plugin'
}
pluginManagement{}块可能只出现在其中一个settings.gradle文件中,其中它必须是文件或初始化脚本中的第一个块。
例6。在每个项目和全局配置pluginManagement
//settings.gradle配置
pluginManagement {
plugins {
}
resolutionStrategy {
}
repositories {
}
}
rootProject.name = 'plugin-management'
//init.gradle配置
settingsEvaluated { settings ->
settings.pluginManagement {
plugins {
}
resolutionStrategy {
}
repositories {
}
}
}
默认情况下,plugins {} DSL解析来自公共Gradle Plugin Portal的插件。许多构建作者还希望从私有的Maven或Ivy存储库解析插件,因为这些插件包含私有的实现细节,或者只是为了对他们的构建可用的插件有更多的控制。
下图是gradle plugin 门户的首页
要指定自定义插件存储库,请使用pluginManagement{}中的repositories{}块:
示例:使用自定义插件库中的插件。
// settings.gradle
pluginManagement {
repositories {
maven {
url './maven-repo'
}
gradlePluginPortal()
ivy {
url './ivy-repo'
}
}
}
这告诉Gradle首先在Maven存储库中查找…/ Maven -repo,然后检查Gradle插件门户,如果在Maven存储库中没有找到插件。如果你不希望Gradle PluginPortal被搜索,省略gradlePluginPortal()行。最后,Ivy存储库在…/ivy-repo将被检查。
pluginManagement{}中的plugins{}块允许在单个位置定义构建的所有插件版本。然后可以通过Plugins{}块通过id将插件应用到任何构建脚本。
以这种方式设置插件版本的一个好处是pluginManagement.Plugins{}没有与构建脚本Plugins{}块相同的约束语法。这允许从gradle.properties中获取插件版本,或者通过另一种机制加载。
示例:通过pluginManagement管理插件版本。
//settings.gradle
pluginManagement {
plugins {
id 'com.example.hello' version "${helloPluginVersion}"
}
}
//build.gradle
plugins {
id 'com.example.hello'
}
//gradle.properties
helloPluginVersion=1.0.0
插件版本从gradle. properties中加载,并在设置脚本中配置,允许插件添加到任何项目,而无需指定版本。
插件解析规则允许你修改在plugins{}块中发出的插件请求,例如,更改请求的版本或显式地指定实现工件坐标。
要添加解析规则,请使用pluginManagement{}块中的resoltionstrategy {}:
示例9。插件解析策略。
settings.gradle
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == 'com.example') {
useModule('com.example:sample-plugins:1.0.0')
}
}
}
repositories {
maven {
url './maven-repo'
}
gradlePluginPortal()
ivy {
url './ivy-repo'
}
}
}
上述配置告诉Gradle使用指定的插件实现工件,而不是使用内置的默认映射,从插件ID到Maven/Ivy坐标。
自定义Maven和Ivy插件库除了实际实现插件的构件外,还必须包含插件标记构件。有关将插件发布到自定义存储库的更多信息,请阅读Gradle Plugin Development Plugin(开发插件和发布插件)。
关于使用pluginManagement{}块的完整文档,请参阅PluginManagementSpec。
由于plugins {} DSL块只允许通过其全局唯一的插件id和版本属性来声明插件,Gradle需要一种方法来查找插件实现工件的坐标。为此,Gradle将使用坐标Plugin .id: Plugin .id. Gradle . Plugin: Plugin .version寻找一个插件标记工件。这个标记需要依赖于实际的插件实现。发布这些标记是由java-gradle-plugin自动完成的。
例如,下面这个来自sample-plugins项目的完整示例展示了如何使用java-gradle-plugin、Maven -publish插件和Ivy -publish插件的组合,将com.example.hello插件和com.example.goodbye插件发布到Ivy和Maven存储库。
示例10。完整的插件发布示例
//build.gradle
plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'ivy-publish'
}
group 'com.example'
version '1.0.0'
gradlePlugin {
plugins {
hello {
id = 'com.example.hello'
implementationClass = 'com.example.hello.HelloPlugin'
}
goodbye {
id = 'com.example.goodbye'
implementationClass = 'com.example.goodbye.GoodbyePlugin'
}
}
}
publishing {
repositories {
maven {
url '../../consuming/maven-repo'
}
ivy {
url '../../consuming/ivy-repo'
}
}
}
在示例目录中运行gradle publish创建以下Maven存储库布局(Ivy布局类似):
例11。应用二进制插件
//build.gradle
apply plugin: 'java'
可以使用插件id来应用插件。在上面的例子中,我们使用缩写“java”来应用JavaPlugin。
与其使用插件id,还可以通过简单地指定插件的类来应用插件:
示例12。按类型应用二进制插件
//build.gradle
apply plugin: JavaPlugin
上面示例中的JavaPlugin符号指的是JavaPlugin。这个类并不严格需要导入,因为在所有构建脚本中都会自动导入org.gradle.api.plugins包(参见默认导入)。
此外,在Groovy中没有必要像在Java中那样附加.class来标识类文字。
已经作为外部jar文件发布的二进制插件可以通过将插件添加到构建脚本类路径中,然后应用该插件来添加到项目中。外部jar可以使用buildscript{}块添加到构建脚本类路径中,如构建脚本的外部依赖项中所述。
示例13。使用buildscript块应用插件
//build.gradle
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
apply plugin: 'com.jfrog.bintray'
例14。应用脚本插件
//build.gradle
apply from: 'other.gradle'
脚本插件是自动解析的,可以从本地文件系统或远程位置的脚本应用。文件系统位置相对于项目目录,而远程脚本位置是用HTTP URL指定的。可以将多个脚本插件(任何一种形式)应用到给定的目标。