Contents

  • 插件做了什么
  • 插件的类型
  • 使用插件
  • 二进制插件
  • 脚本插件
  • 发现社区插件
  • 了解插件的更多

Gradle 的核心是故意为现实世界的自动化提供很少的东西,所有有用的特性,例如编译Java 代码的能力-通过插件增加 …
增加了新的任务(例如 JavaCompile),领域对象(例如 SourceSet),约定(例如Java source位于 src/main/java),同样扩展了核心对象以及来自其他插件的对象 …
那么我们该如何使用插件(围绕插件的技术和概念) …

插件能做什么

应用一个插件到项目允许插件去扩展项目的能力,它能够做以下的事情:

  • 扩展Gradle 模型(例如,增加一个能够配置的新的DSL 元素)
  • 根据约定配置这个项目(例如,增加新的任务或者配置合理的默认值)
  • 应用特定的配置(例如,增加组织仓库或者强制标准)

通过应用插件,而不是为了项目构建脚本增加逻辑,我们能够获得大量的好处 ..

  • 在跨越多个项目中促进重用并且减少维护类似逻辑的消耗 ..
  • 允许高度的模块化,增加合作性以及组织性 ..
  • 封装命令式逻辑 并且允许构建脚本 尽可能声明式 … 更容易阅读 ..

插件的类型

在Gradle中插件分为两个大类,二进制插件和脚本插件,二进制插件要么通过实现Plugin 插件接口程序式编写或者使用Gradle的DSL 语言的其中一种进行编写..
二进制插件可以驻留在构建脚本中、项目层次结构中或外部插件 jar 中 ..
脚本插件时额外的构建脚本 - 它们进行更神层次的配置构建并通常实现了一种声明式的方式去维护这个构建 ,它们在构建中使用 .. 尽管它们可能是外部化的并且从远程位置可以进行访问 ..
一个插件经常从脚本插件开始(因为它容易编写),然后更加的含义强化,可能迁移为一个二进制插件(能够更容易的测试并且在多项目或者组织中共享) …

使用插件

为了将构建逻辑封装在插件中,Gradle 需要执行两个步骤,第一步,它需要解析这个插件,其次它需要应用插件到目标上,通常是Project.
解析一个插件意味着需要发现包含给定插件的Jar的正确版本并且增加它到脚本类路径中 ..
一旦一个插件被解析了,那么它的API 能够在构建脚本中使用 …
脚本插件自我解析(自我明白) - 在应用它们的时候 它们能够从指定文件路径或者提供URL 中解析…
核心的二进制插件作为Gradle 发行包的一部分能够自动解析 ..
应用一个插件意味着实际上执行了插件的apply方法到你想要通过此插件增强项目的能力 …
应用一个插件时幂等的,那就是你能够安全的应用一个插件一次或者多次(而没有副作用)
大多数通用情况下 使用一个插件是同时解析并应用到当前项目中,因此这是一种通用情况 ..
它是推荐构建作者使用 PluginDependenciesSpec plugins 脚本块进行插件应用
它会通知解析并应用插件(只需一步)

二进制插件

你能够通过插件的id ,通常是全局唯一的标识符,或者插件的名称..
核心插件是故意提供简单的名称,例如’java’表示核心The Java Plugin,其他二进制插件必须设定为插件的完全限定形式(例如,com.github.foo.bar).. 尽管某些遗留的插件仍然利用的简单的方式,不合法的形式 .. 提供插件id依赖于你使用plugin DSL 还是构建脚本块 ..

二进制插件的定位

一个插件时任何实现Plugin 接口的类,Gradle 提供的核心插件会自我解析,但是非核心的二进制插件需要在应用之前解析 , 它们接收以下一些方式:

了解如何自定义你的插件,查看 Custom Plugins

使用plugin DSL 应用插件

插件 DSL 提供了一种简洁方便的方式来声明插件依赖项,它与Gradle 插件门户提供一种容易的方式访问核心插件以及社区插件 …
plugin DSL 块是一个 PluginDependenciesSpec的实例 …

  1. plugins {
  2. id 'java'
  3. }

了解更多如何通过plugin DSL 应用插件的详情 …

plugins DSL 的限制

通过这种方式增加插件到项目中具有更多便利的语法 ..
这个plugins DSL 被Gradle 使用一种更早并且更快速的方式去判断插件处理 …
这允许Gradle 做一些智能的事情,例如:

  • 优化插件类的加载和重用
  • 允许使用不同依赖的不同插件
  • 为编辑提供有关构建脚本中潜在属性和值的详细信息,以帮助编辑。

这需要插件能够被Gradle在构建脚本其余部分执行之前以及更快速的抓取.
它也需要插件的定义能够有些静态 …

plugins {} 块和传统的apply方法有一些关键不同. 这里有一些约束,有些是临时限制并且这个机制仍然处于开发之中并且有些继承至新的方式 …

约束的语法

此 plugins 代码块不支持任意的代码,它是被约束的,为了实现幂等(每次产生相同的结果)以及无副作用(每次执行对于Gradle 来说都是安全的) …
它的形式是:

plugins {
    id «plugin id»                                            
    id «plugin id» version «plugin version» [apply «false»]   
}

任何其他的语句都会导致编译错误 …
查看plugin version management 如何使用变量定义插件的版本 …
plugins {} 块必须作为构建脚本的顶级语句,它内嵌到另外结构中…
例如(if / for-loop)

仅仅能够在构建脚本以及配置文件中使用

plugins 脚本块当前仅仅能够使用在项目的构建脚本 以及 settings.gradle 文件中,它不能够使用在脚本插件中或者初始化脚本中 …
未来也许会移除这个限制…
如果 plugins {} 块的限制是高昂的,推荐的方法是使用 buildscript {} 块应用插件。

应用具有相同版本的外部插件到子项目中

你如果你位于多项目构建中,你可能想要应用插件到某些构建的子项目中 …
但不是根项目,默认的plugins 代码块的行为会立即解析并应用插件 ..
但是你能够使用apply false 语法去告诉Gradle 不应用插件到当前的项目中并且
子项目就可以在构建脚本中使用plugins{} 块并不需要版本来应用插件 …

include 'hello-a'
include 'hello-b'
include 'goodbye-c'
plugins {
    id 'com.example.hello' version '1.0.0' apply false
    id 'com.example.goodbye' version '1.0.0' apply false
}
plugins {
    id 'com.example.hello'
}
plugins {
    id 'com.example.hello'
}
plugins {
    id 'com.example.goodbye'
}

甚至可以更棒,你能够封装外部插件的版本 - 通过组合构建逻辑(通过使用你自己的 convention plugins )… 将插件版本封印到插件中 …

应用来自buildSrc 目录的插件

你能够应用位于项目的buildSrc目录的插件 - 只要它们定义了ID,以下的例子展示了如何关联一个插件的实现类(例如my.Plugin), 通过在buildSrc中为它定义一个”my-plugin”

plugins {
    id 'java-gradle-plugin'
}

gradlePlugin {
    plugins {
        myPlugins {
            id = 'my-plugin'
            implementationClass = 'my.MyPlugin'
        }
    }
}

这个插件能够通过ID 正常应用 …

plugins {
    id 'my-plugin'
}

上面使用的gradlePlugin 属于Gradle Plugin Development Plugin的内容,详情了解此文章 …

插件管理

pluginManagement {} 仅仅能够出现在settings.gradle 文件,且必须作为该文件的第一个block ,或者出现在初始化脚本 .
为每个项目配置插件管理或者全局管理
当前构建全局配置

pluginManagement {
    plugins {
    }
    resolutionStrategy {
    }
    repositories {
    }
}
rootProject.name = 'plugin-management'

为每一个构建配置 …

settingsEvaluated { settings ->
    settings.pluginManagement {
        plugins {
        }
        resolutionStrategy {
        }
        repositories {
        }
    }
}

自定义插件仓库

默认plugins DSL 从Gradle 插件门户解析插件 ..
许多构建者想要从私有Maven / lvy 仓库中解析插件 - 因为插件包含专属的实现详情 …
或者仅仅在它们构建中可用的插件进行更多控制 ..
为了指定自定义插件仓库,使用 repositories {} 块到pluginMangement {}中 …

pluginManagement {
    repositories {
        maven {
            url './maven-repo'
        }
        gradlePluginPortal()
        ivy {
            url './ivy-repo'
        }
    }
}

这告诉Gradle 首先查看 ../maven-repo 解析插件然后检查Gradle Plugin 门户(如果没有在第一个位置中发现插件).. 如果你不想要Gradle 插件门户被查询,注释掉配置它这一行即可 …
最终将会检查 ../ivy-repo仓库 ..

插件版本管理

在pluginMangement {} 中的plugins {}块 允许当前构建中的所有插件版本能够在一处定义 ..
插件能够通过在任意的构建脚本中通过 plugins {} 块进行构建 ….
统一配置插件版本的好处是,这种方式 pluginMangement.plugins{} 没有和plugins {} 相同的约束语法 …
这允许插件的版本能够来自gradle.properties,或者通过其他机制加载 …

pluginManagement {
  plugins {
        id 'com.example.hello' version "${helloPluginVersion}"
    }
}
plugins {
    id 'com.example.hello'
}
helloPluginVersion=1.0.0

当然也可以来自扩展属性的版本定义 ….

ext {
    ...
}

插件解析规则

插件解析规则允许你修改plugins 脚本块中的插件请求 ..
例如改变请求的版本 或者显式的指定实现工件的坐标 ..
非常常见的一个例子就是统一一个插件的版本或者替换插件实现 …
在pluginMangement {} 中增加resolutionStrategy {} …

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'
        }
    }
}

例如这里对于请求id的命名空间如果为 ‘com.example’,这使用模块 …中的插件 …
这将告诉Gradle 使用特定的插件实现工件代替内置的默认的来自Maven / lvy坐标对应的插件id 映射 …
自定义的Maven 以及 lvy 插件仓库必须包含 plugin marker artifacts ,除了实现此插件的工件之外 … 有关发布插件到自定义的仓库中了解 Gradle Plugin Development Plugin
查看 PluginManagementSpec 了解使用pluginManagement {} 的完整文档 …

Plugin Marker Artifacts

因此plugins {} DSL 块仅仅允许通过全局唯一插件id / version 属性声明插件 ..
Gradle 需要一种方式去查询插件实现工件的坐标 ..
为了这样做,Gradle将会为插件 查询具有plugin.id:plugin.id.gradle.plugin:plugin.version坐标的Plugin Marker Artifact …
这个marker 需要有一个对实际插件实现的依赖 。。。
通过Gradle Plugin Development Plugin自动发布这些markers …
举个例子,以下来自sample-plugins项目的完整例子展示了通过java-gradle-plugin、maven-publish、ivy-publish 插件的合并如何发布一个com.example.hello 插件 以及 com.example.goodbye 插件 到 lvy 以及 maven 仓库 ..

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 仓库布局(lvy 结构是类似的) …
Using Gradle Plugins[TODO] - 图1

遗留的插件应用

随着PluginDependenciesSpec plugins DSL的引入,用户应该有一些使用遗留的应用插件方法的怨言,记录在这里是由于不能使用plugins DSL(由于限制),如何让它们正常工作 …

应用二进制插件

apply plugin: 'java'

插件能够使用插件id,上面的例子中使用了 ‘java’ 应用 The Java Plugin.
除了使用插件id,插件能够通过指定插件的类进行应用 …

apply plugin: JavaPlugin

这个类没有限制必须被导入,因为org.gradle.api.plugins包自动导入到所有的构建脚本中了 …
点击查看 Default imports
因此,它不需要追加.class 来标识一个类(就如在Groovy 以及 java中) …

使用构建脚本块应用插件

二进制插件已经发布到外部的jar文件中,它们能够增加到项目中 - 通过增加插件到构建脚本类路径中然后应用插件 ..
外部的jar 能够通过buildscript {} 块增加到构建脚本类路径上 ..
详细查看External dependencies for the build script

buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
    }
}

apply plugin: 'com.jfrog.bintray'

脚本插件

apply from: 'other.gradle'

脚本插件自动的解析并应用来自本地文件系统或者远程位置的插件 …
文件系统的位置是相对于项目目录的 ..
然而远程脚本位置需要使用HTTP URL 进行指定 …
可以将多个脚本插件(任何一种形式)应用于给定目标 …

发现社区插件

查看Gradle Plugin portal 了解更多的社区插件

在插件中了解更多

了解插件的内部工作原理,请查看Custom Plugins