本文内容大部分来自 Gradle 官方文档,英文 OK 的同窗能够直接看官方文档。 本文示例代码已放在 zjxstar 的 GitHub。html
提及 Gradle 插件,不得不感叹 Gradle 的设计很是棒。 Gradle 自己提供基本的概念以及核心框架,而其余的场景逻辑均可以经过插件扩展的方式来实现。对于 Android 开发来讲,经常使用的插件就是 Android Gradle 插件和 Java 插件了,咱们会在下一篇文章中详细介绍 Android 插件。java
本文主要学习 Gradle 插件的基础知识以及如何编写自定义插件。android
Gradle 插件一般用来封装一些可重用的编译逻辑,能够用来扩展项目的功能,帮助项目在构建过程当中处理一些特殊逻辑。git
总之,咱们只要根据插件约定的接口,使用它提供的任务、方法或者扩展,就能够帮助咱们进行项目构建。github
Gradle 中的插件种类分为两种,一种是脚本插件,另外一种是二进制插件。而应用插件的方式也有多种,下面咱们详细介绍。api
所谓的脚本插件就是咱们自定义的以 .gradle 为后缀的脚本文件,严格意义上来讲,它只是一个可执行脚本。应用它就是把整个脚本加载到主 build.gradle 脚本中,从而辅助构建。应用方式以下:网络
apply from: '脚本文件名' // 好比:apply from: 'project_task_examples.gradle'
复制代码
它不只能够应用本地脚本,也能够应用网络上的脚本,这样的话,就必须使用 HTTP URL 了。闭包
举例说明:app
在前两章的 Project 和 Task 的学习中,咱们在 app 模块的 build.gradle 文件中写了不少示例,咱们把这些示例都提到一个单独的 gradle 脚本中,而后在 build.gradle 中应用它。新的脚本文件命名: project_task_examples.gradle ,只须要使用 apply from: 'project_task_examples.gradle' 应用便可。框架
虽然它不算真正的插件,但也不能忽视它的做用,它是脚本文件模块化的基础。咱们能够把庞大的脚本文件进行分块、分段整理,拆分红一个个共用的、职责分明的文件,而后使用 apply from
应用它们。这样可让咱们的脚本更加清晰、简单、方便和快捷。
二进制插件是实现了 org.gradle.api.Plugin
接口的插件(通常都是打包在 jar 里独立发布),它们拥有 plugin id ,这个 id 是插件全局惟一的标识或名称。咱们须要经过
apply plugin: 'plugin id'
复制代码
的方式应用二进制插件。好比 Android 的 Application 插件,咱们经过 Android Studio 建立 Android 工程时,在 app 模块中会自动经过 apply plugin: 'com.android.application' 来引入 Application 插件。
对于 Gradle 自带的核心插件都有一个容易记的短名,好比 Java 插件,经过 apply plugin:'java' 应用。其实它对应的类型是 org.gradle.api.plugins.JavaPlugin
,因此还能够经过该类型进行应用:apply plugin:org.gradle.api.plugins.JavaPlugin 。因为包 org.gradle.api.plugins 是默认导入的,因此咱们能够去掉包名直接写为: apply plugin:JavaPlugin 。
其实 apply 方法有重载方法:
void apply(Closure var1);
void apply(Action<? super ObjectConfigurationAction> var1);
void apply(Map<String, ?> var1);
复制代码
以前使用的是传入 Map 参数的方式,咱们也能够换成闭包的方式。
apply {
plugin 'java'
}
复制代码
plugins DSL 是一种新的插件应用方式,Gradle 2.1 以上版本才可使用。它的语法以下:
plugins {
id «plugin id» // (1)
id «plugin id» version «plugin version» [apply «false»] // (2)
}
复制代码
方式(1)是提供给 Gradle 核心插件或者构建脚本中已有的插件的。方式(2)提供给须要解析的二进制插件,这些插件要托管在 plugins.gradle.org/ 网站上。
示例:
plugins {
id 'java'
}
plugins {
id 'com.jfrog.bintray' version '0.4.1'
}
复制代码
固然,这种使用方式有必定的限制:
插件的类型和应用方式就介绍到这,下面咱们要学习如何自定义插件,来知足本身的业务逻辑。
自定义插件的关键点就是要实现 org.gradle.api.Plugin
接口,重写 apply 方法来实现本身的业务逻辑。本讲中使用的示例都是构建 Task 的简单示例,感兴趣的同窗的能够自行深刻。
这里有三种方式来承载自定义插件的代码:构建脚本、buildSrc 项目、独立项目。
咱们能够直接在构建脚本中编写自定义插件的代码。 这样作的好处是插件能够自动编译并包含在构建脚本的类路径中,而无需执行任何操做。 可是,这样定义的插件在构建脚本以外是不可见的,即没法在其定义的构建脚本以外重用该插件。
示例:
/* 自定义插件:直接在脚本文件中定义,其局限性较大 */
// app的build.gradle文件中
// 定义一个Extension类用来接收脚本传的参数
class CustomExtensionA {
String message = 'Hello Custom PluginA'
// 还能够定义其余配置参数
String greeter = 'Welcome Gradle Plugin'
}
// 定义一个自定义插件类,实现Plugin接口
class CustomPluginA implements Plugin<Project> {
@Override
void apply(Project target) {
// 将Extension注册给Plugin
def extension = target.extensions.create('customA', CustomExtensionA)
// 定义一个任务
target.task('CustomPluginTaskA') {
doFirst {
println 'this is custom plugin A task A'
}
doLast {
// 使用Extension传入的参数
println extension.message
println extension.greeter
}
}
}
}
复制代码
例子中,咱们建立一个 CustomPluginA 类,实现 Plugin 接口,重写 apply 方法。在 apply 方法中使用 project 建立一个名为 CustomPluginTaskA 的任务。该插件还能够接受扩展,即定义了一个 CustomExtensionA 类,里面有 message 和 greeter 两个属性。在 apply 方法中,经过 project.extensions.create(扩展名, 扩展类) 就能够完成自定义扩展的注册。
应用该插件只须要在 build.gradle 文件中使用 apply plugin 引入便可。
// 使用插件CustomPluginA,这里必须使用插件类名,而不是字符串
// 使用gradlew -q CustomPluginTaskA查看插件是否生效
apply plugin: CustomPluginA
// 配置CustomExtensionA,须要使用注册名,这里是customA
customA.message = 'Hi from PluginA'
复制代码
引入插件后,能够像运行普通任务同样经过命令运行插件中定义的 Task 。至于扩展的使用,只需使用扩展名声明对应属性便可。
咱们能够在工程里新建一个名为 buildSrc 的模块来开发自定义插件,其过程和写 Android Library 相似。buildSrc 模块中的代码会自动被 Gradle 加载,Gradle 将负责编译和测试插件并使其在构建脚本的类路径中可用。 这种方式定义的插件对于构建中的每一个构建脚本都是可见的。 可是,它在构建以外是不可见的,所以没法在其定义的构建以外重用该插件。
新建 buildSrc 模块:
该模块很是简单,只须要有 src/main/groovy 目录用来存放源代码便可(由于使用的 Groovy 语言编写,因此是 groovy,若是使用 java 或者 kotlin ,换成对应目录便可)。
在 build.gradle 脚本中依赖 gradleApi 和 Groovy 插件。
// 依赖groovy插件
plugins {
id 'groovy'
}
dependencies {
implementation gradleApi()
implementation localGroovy()
}
复制代码
接着就是写代码了,这个过程和“构建脚本”小节中同样,只是将代码放在了 groovy 文件中而已。
// 在单独的groovy文件中定义插件类
class CustomPluginB implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('CustomPluginTaskB') {
doFirst {
println 'This is custom plugin TaskB'
}
}
}
}
复制代码
最后,就是在 app 模块中引入该插件。
/* 自定义插件:引用在buildSrc模块中定义的插件,使用插件类名的全限定名 */
// 使用gradlew -q CustomPluginTaskB查看插件是否生效
apply plugin: com.zjx.happy.plugin.CustomPluginB
复制代码
因为构建过程当中 Gradle 会自动加载 buildSrc 模块中的代码,因此直接使用插件类的全限定名便可。
咱们能够为插件建立单独的项目。将该项目发布成一个 JAR ,就能够在多个地方使用它。这种方式是比较经常使用的。
首先,和 buildSrc 项目同样建立一个新模块,模块名没有要求。
和 buildSrc 不一样的是,它多出了一个 resources 资源目录。一样的,这个模块里也要依赖 gradleApi 和 Groovy 插件。
而后,在 groovy 目录下完成代码的编写。这里依然只是写个简单示例。
class CustomPluginC implements Plugin<Project> {
@Override
void apply(Project project) {
project.task('CustomPluginTaskC') {
doFirst {
println 'This is Custom Plugin TaskC'
}
}
}
}
复制代码
至此,插件的核心已经准备好了,如今要给这个插件设置一个 plugin id 。须要在 resources 目录下,建立 META-INF 目录。而后在 META-INF 目录下再建立一个 gradle-plugins 目录。( 注意: 这里建立目录时请逐级建立。不要经过一次性输入 META-INF.gradle-plugins 的目录名方式建立,由于 resources 目录没法像代码目录那样自动识别包名并分级,它只会建立一个目录,这样是不正确的。)
目录建立好后,咱们须要在该目录下,新建一个 properties 文件,而文件名就是插件的 plugin id 。该 properties 文件中须要声明插件的实现类,语法以下:
# 建立该目录时必定要注意,要一级一级的建立,先建立META-INF,再建立gradle-plugins,而不是直接META-INF.gradle-plugins
# 由于不是src的目录,因此没法自动识别 . 号
# implementation-class是固定的,等号右边是插件实现类的全限定类名
implementation-class=com.zjx.happy.plugin.CustomPluginC
复制代码
详细目录结构如图:
本示例中的插件的 plugin id 就是 com.happy.custompluginc 。那么 plugin id 有哪些规范呢?
插件准备好后,咱们要将其发布出去,通常使用 Maven 。
// build.gradle中
apply plugin: 'maven' // 引入 maven 插件
repositories {
mavenCentral()
}
// 将该插件上传到本地Maven库
group='com.happy.plugin'
version='1.0.0'
// 经过gradlew :customPlugin:uploadArchives命令上传
uploadArchives {
repositories {
mavenDeployer {
//本地的Maven地址设置为../repos
repository(url: uri('../repos'))
}
}
}
复制代码
使用 gradlew :customPlugin:uploadArchives 命令上传。示例中会在工程目录下建立 repos 目录,里面存放了 customPlugin 的 jar 包和 pom 信息。
如何应用独立模块自定义的插件呢?其方法和 Android 插件同样。
在根 build.gradle 文件中声明插件依赖:
dependencies {
// 这是Android插件
classpath 'com.android.tools.build:gradle:3.3.1'
// 这是刚自定义的插件
classpath 'com.happy.plugin:customPlugin:1.0.0'
}
复制代码
同步以后,就能够在 app 模块中使用 apply plugin 引入了。
/* 自定义插件:引用已经发布到Maven的插件 */
apply plugin: 'com.happy.custompluginc' // 这个plugin id就是properties文件的文件名
复制代码
最后,使用命令 gradlew -q CustomPluginTaskC 验证插件是否生效。
Gradle 插件相关的内容就这么多,总体上看仍是很简单的。如今社区中的第三方插件不少,咱们能够根据业务须要适当引用。固然,咱们也彻底能够本身实现适合业务的插件。通常 APM 类项目中 中就须要实现自定义插件来完成代码的自动插桩,它须要利用到 Android 提供的 Gradle-api 中的 Transform 。后续的文章中咱们会学习 Transform 。