通常我们会想要将一个非常有用的task共享给多个项目使用,Gradle插件正可以解决这一问题。Gradle插件是非常强大的,如Java插件,一行代码:apply plugin: 'java'
,就可以使用Java插件实现代码的编译、测试和打包成JAR文件;在android中,我们经常使用:apply plugin: 'com.android.application'
来加载android插件。
1、首先看一下项目的结构:
从上到下介绍目录:plugin和project是两个根项目,分别用来发布插件和测试使用插件。plugin项目中的代码默认放在groovy目录下,自定义的插件和task代码都要放到该目录下的包中,resources/META-INF/gradle-plugins目录下放置的是插件的配置文件,如HelloChenPlugin.properties文件暴露了插件的名字叫做HelloChenPlugin,在这个配置文件中将插件的全限定名赋值给键implementation-class
:
implementation-class=com.chen.plugins.BuildPlugin
project项目用来测试自定义插件的使用,包含了一个model子项目,和普通android工程项目结构是一样的。
2、插件的自定义(plugin工程):
①编写插件文件:编写一个插件要实现org.gradle.api. Plugin< Project >
接口,该接口只提供了一个方法:void apply(Project project);
。在com.chen.plugins
包下新建BuildPlugin.groovy文件,代码如下,插件扩展机制,可以让我们在闭包中为task所需的属性赋值,在后面的使用扩展的时候会看到它的作用,BuildPluginExtension
类和BuildTasksParam
是两个实体类。
class BuildPlugin implements Plugin<Project> {
static final String EXTENSION_NAME = 'HelloChen'
@Override
void apply(Project project) {
/**注册一个扩展容器,扩展容器可以使我们在一个闭包中为task赋值*/
project.extensions.create(EXTENSION_NAME, BuildPluginExtension)
addTask(project)
}
private void addTask(Project project) {
project.tasks.withType(AbstractTask) {
/**查找扩展容器中已配置的属性*/
def extension = project.extensions.findByName(EXTENSION_NAME)
/**将闭包中的扩展属性值赋给 AbstractTask 的相关属性*/
conventionMapping.myId = { extension.myId }
conventionMapping.myName = { extension.myName }
conventionMapping.myGroup = { extension.myGroup }
}
addMyTask(project)
}
private void addMyTask(Project project) {
/**添加一个task,task名字是myTask,定制任务是 MyTask*/
project.task('myTask', type: MyTask) {
/**为 MyTask 的myAddress属性赋值*/
conventionMapping.myAddress = {
getAddress(project)
}
}
}
private String getAddress(Project project) {
/**首先判断project中有没有myAddress(一般在gradle.properties文件中定义)属性,没有则使用配置的属性值*/
project.hasProperty('myAddress') ? project.myAddress : project.extensions.findByName(EXTENSION_NAME).myAddress
}
}
②编写task文件:我定义了两个task,一个抽象的task:AbstractTask,一个继承自AbstractTask:MyTask,在com.chen.plugins.tasks
包下,代码如下:
abstract class AbstractTask extends DefaultTask {
/**可以配置的task属性:
* Gradle 自动为所有属性生成getter和setter方法*/
@Input
String myId
@Input
String myName
@Input
String myGroup
AbstractTask(String description) {
this.description = description
/**指定task的group*/
group = 'CustomPlugin'
}
/**定义一个action*/
@TaskAction
void start() {
BuildTasksParam param = new BuildTasksParam()
/**直接使用getter方法获取属性值*/
param.setMyId(getMyId())
param.setMyName(getMyName())
param.setMyGroup(getMyGroup())
try {
executeAction(param)
}
catch (Exception e) {
logger.error "Failed to execute MyTask ", e
throw new GradleException(e.message)
}
}
abstract void executeAction(BuildTasksParam param)
}
class MyTask extends AbstractTask {
@Input
String myAddress
MyTask() {
super('Returns the basic information about an application.')
}
@Override
void executeAction(BuildTasksParam param) {
/**拿到映射中的赋值,并打印出来*/
logger.quiet "myId is : $param.myId"
logger.quiet "myName is : $param.myName"
logger.quiet "myGroup is : $param.myGroup"
logger.quiet "myAddress is : " + getMyAddress()
}
}
③配置HelloChenPlugin.properties文件:该文件为插件添加一个短名字,短名字就是文件名,不然每次使用插件都要这样:apply plugin: 'com.chen.plugins.BuildPlugin'
,配置后只要这样:apply plugin: 'HelloChenPlugin'
,该配置文件如下,只有一行,为短名字设置真正的插件的全限定名:
implementation-class=com.chen.plugins.BuildPlugin
④构建脚本编写:
apply plugin: 'groovy'
/**应用maven插件来发布插件工件*/
apply plugin: 'maven'
/**定义工件的group、name 和 version*/
group = 'com.chen.plugins'
archivesBaseName = 'chen-plugin'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
/**定义对groovy和gradle api的依赖*/
compile localGroovy()
compile gradleApi()
}
uploadArchives {
repositories {
/**配置Maven部署器,将工件上传到本地目录,这里是放到与该项目同级目录的repo目录下*/
mavenDeployer {
repository(url: "file://$projectDir/../repo")
}
}
}
执行gradle tasks命令,可以看见有一个uploadArchives任务:
执行gradle uploadArchives命令发布工件,在项目中多出来一个repo新目录,它包含了插件的JAR文件和POM文件,该目录的结构如下图:
3、使用自定义插件(project工程):使用插件就很简单了:
①在根目录的build.gradle构建脚本如下:
allprojects {
group = 'com.chen.app'
version = '1.0.1'
buildscript {
repositories {
/**指定本地maven仓库*/
maven { url "file://$projectDir/../../repo" }
mavenCentral()
}
dependencies {
/**构建脚本并不知道外部插件的存在,除非将插件添加到 classpath*/
classpath 'com.chen.plugins:chen-plugin:1.0.0'
}
}
}
subprojects {
apply plugin: 'java'
}
②gradle.properties文件配置:
myAddress=shanghai
③model子项目的build.gradle构建脚本如下:这里可以看到插件扩展机制的作用,可以直接在HelloChen
扩展中为myTask任务赋值:
/**使用自定义的插件*/
apply plugin: 'HelloChenPlugin'
/**使用 HelloChen 扩展为 myTask 赋值*/
HelloChen {
myId = 'my id'
myName = 'hello chen'
myGroup = 'my group'
myAddress = 'my address'
}
④执行myTask任务:gradle myTask输出如下,这里可以看到gradle.perproties文件中的属性替换掉了我们在扩展中的值:
> Task :model:myTask
myId is : my id
myName is : hello chen
myGroup is : my group
myAddress is : shanghai
综上就是Gradle自定义插件使用的全部了,在这里只将插件发布到了本地maven,实际中需要发布到服务器实现所有开发者共同使用,只需要修改maven发布和使用时maven仓库的地址即可,当然也可以发布到mavenCentral()。上述代码地址:https://github.com/ChenSWD/CopyGradleInAction/tree/master/chapter08-gradle%E6%8F%92%E4%BB%B6/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8F%92%E4%BB%B6–%E6%B3%A8%E9%87%8A