一、Gradle 插件概述
自定义 Gradle 插件的本质就是把逻辑独立的代码进行抽取和封装,以便于我们更高效地通过插件依赖这一方式进行功能复用。
而在 Android 下的 gradle 插件共分为 两大类,如下所示:
1、
脚本插件
:同普通的 gradle 脚本编写形式一样,通过 apply from: 'JsonChao.gradle' 引用。2、
对象插件
:通过插件全路径类名或 id 引用,它主要有 三种编写形式,如下所示:-
1)、在当前构建脚本下直接编写。
2)、在 buildSrc 目录下编写。
3)、在完全独立的项目中编写。
下面????,我们就先来看看如何编写一个脚本插件。
二、脚本插件
同普通的 gradle 脚本编写形式一样,我们既可以写在 build.gradle 里面,也可以自己新建一个 gradle 脚本文件进行编写。
class PluginDemo implements Plugin<Project> {
@Override
void apply(Project target) {
println 'Hello author!'
}
}
复制代码
然后,在需要使用的 gradle 脚本中通过 apply plugin:pluginName
的方式即可引用对应的插件。
apply plugin: PluginDemo
复制代码
三、运用 buildSrc 默认插件目录
在完成几个自定义 Gradle 插件之后,我发现 在 buildSrc 目录下编写插件的方式是开发效率最高的,首先,buildSrc 是默认的插件目录,其次,在 buildSrc 目录下与独立工程的插件工程一样,也能够发布插件,这里仅仅只需对某些配置做一些调整即可,下面,我们就来看看如何来创建一个自定义 Gradle 插件。
1、创建一个能运行起来的空 Plugin
首先需要了解的是,buildSrc 目录是 gradle 默认的构建目录之一,该目录下的代码会在构建时自动地进行编译打包,然后它会被添加到 buildScript 中的 classpath 下,所以不需要任何额外的配置,就可以直接被其他模块中的 gradle 脚本引用。此外,关于 buildSrc,我们还需要注意以下 两点:
1)、buildSrc 的执行时机不仅早于任何⼀个 project(build.gradle),而且也早于 settings.gradle。
2)、settings.gradle 中如果配置了 ':buildSrc' ,buildSrc ⽬录就会被当做是子 Project , 因会它会被执行两遍。所以在 settings.gradle 里面应该删掉 ':buildSrc' 的配置。
插件 moudle 创建三部曲
1)、新建一个 module,并将其命名为 buildSrc。这样,Gradle 默认会将其识别会工程的插件目录。
2)、src 目录下删除仅保留一个空的 main 目录,并在 main 目录下新建 1 个 groovy 目录与 1 个 resources 目录。
3)、将 buildSrc 中的 build.gradle 中的所有配置删去,并配置 groovy、resources 为源码目录与相关依赖即可。配置代码如下所示:
apply plugin: 'groovy'
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
// Groovy DSL
implementation localGroovy()
// Gradle DSL
implementation gradleApi()
// Android DSL
implementation 'com.android.tools.build:gradle:3.6.2'
// ASM V7.1
implementation group: 'org.ow2.asm', name: 'asm', version: '7.1'
implementation group: 'org.ow2.asm', name: 'asm-commons', version: '7.1'
}
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
resources {
srcDir 'src/main/resources'
}
}
}
复制代码
插件创建二部曲
1)、首先,在我的 main 目录下创建一个递归文件夹 "com.json.chao.study",里面直接新建一个名为 CustomGradlePlugin 的普通文件。然后,在文件中写入 'class CustomGradlePlugin' ,这时 CustomGradlePlugin 会被自动识别为类,接着将其实现 Plugin 接口,其中的 apply 方法就是插件被引入时要执行的方法,这样,自定义插件类就基本完成了,CustomGradlePlugin 类的代码如下所示:
/**
* 自定义插件
*/
class CustomGradlePlugin implements Plugin<Project> {
/**
* 插件被引入时要执行的方法
* @param project 引入当前插件的 project
*/
@Override
void apply(Project project) {
println "Hello plugin..." + project.name
}
}
复制代码
2)、接着,在 resources 目录下创建一个 META-INF.gradle-plugins 的递归目录,里面新建一个 "com.json.chao.study.properties" 文件,其中 '.properties' 前面的名字即为 自定义插件的名字,在该文件中,我们需要标识该插件对应的插件实现类,代码如下所示:
implementation-class=com.json.chao.study.CustomGradlePlugin
复制代码
这样,一个最简单的自定义插件就完成了。接着,我们直接在 app moudle 下的 build.gradle 文件中使用 'apply plugin: 'com.json.chao.study' 引入我们定义好的插件然后同步工程即可看到如下输出:
...
> Configure project :app
Hello plugin...app
...
复制代码
可以看到,通过 id 引用的方式,我们可以隐藏类名等细节,使得插件的引用变得更加容易。
2、使用自定义 Extension 与 Task
1、自定义 Extension
在 深度探索 Gradle 自动化构建技术(三、Gradle 核心解密) 一文中我们讲解了如何创建一个版本信息管理的 task,这里我们就可以直接将它接入到 gradle 的构建流程之中。
为了能让 App 传入相关的版本信息和生成的版本信息文件路径,我们需要一个用于配置版本信息的 Extension,其实质就是一个实体类,如下所示:
/*
* Description: 负责 Release 版本管理的扩展属性区域
*
* @author quchao
*/
class ReleaseInfoExtension {
String versionName;
String versionCode;
String versionInfo;
String fileName;
}
复制代码
然后,在我们的 CustomGradlePlugin 的 apply 方法中加入下面代码去创建用于设置版本信息的扩展属性,如下所示:
// 创建用于设置版本信息的扩展属性
project.extensions.create("releaseInfo", ReleaseInfoExtension.class)
复制代码
在 project.extensions.create 方法的内部其实质是 通过 project.extensions.create() 方法来获取在 releaseInfo 闭包中定义的内容并通过反射将闭包的内容转换成一个 ReleaseInfoExtension 对象。
最后,我们就可以在 app moudle 的 build.gradle 脚本中使用 releaseInfo 去配置扩展属性,代码如下所示:
releaseInfo {
versionCode = "1"
versionName = "1.0.0"
versionInfo = "第一个版本~"
fileName = "releases.xml"
}
复制代码
2、自定义 Task
使用自定义扩展属性 Extension 仅仅是为了让使用插件者有配置插件的能力。而插件还得借助自定义 Task 来实现相应的功能,这里我们需要创建一个更新版本信息的 Task,我们将其命名为 ReleaseInfoTask,其具体实现代码如下所示:
/**
* 更新版本信息的 Task
*/
class ReleaseInfoTask extends DefaultTask {
ReleaseInfoTask() {
// 1、在构造器中配置了该 Task 对应的 Task group,即 Task 组,并为其添加上了对应的描述信息。
group = 'version_manager'
description = 'release info update'
}
// 2、在 gradle 执行阶段执行
@TaskAction
void doAction() {
updateVersionInfo();
}
private void updateVersionInfo() {
// 3、从 realeaseInfo Extension 属性中获取相应的版本信息
def versionCodeMsg = project.extensions.releaseInfo.versionCode;
def versionNameMsg = project.extensions.