概述
又开始了一个新的系列,这个系列学习Gradle,目标就是彻底理解Gradle,主要还是做下自己理解的笔记,防止忘记
Gradle系列(一):Groovy学习
Gradle学习系列(二):Gradle核心解密
Gradle学习系列(三):Gradle插件
简介
Gradle本身只是提供了基本的核心功能,其他的特性比如编译Java源码的能力,编译Android工程的能力等等就需要通过插件来实现了。
要想应用插件,需要把插件应用到项目中,应用插件通过 Project.apply()
方法来完成。
在Gradle中一般有两种类型的插件,分别叫做脚本插件
和对象插件
。
脚本插件
是额外的构建脚本,它会进一步配置构建,可以把它理解为一个普通的build.gradle。
对象插件
又叫做二进制插件,是实现了Plugin接口的类,下面分别介绍如何使用它们。
脚本插件
比如我们在项目的根目录创建一个utils.gradle
def getxmlpackage(boolean x){
def file=new File(project.getProjectDir().getPath()+"/src/main/AndroidManifest.xml");
def paser = new XmlParser().parse(file)
return paser.@package
}
ext{
getpackage = this.&getxmlpackage
}
这就是一个简单的脚本插件,然后在app moudle引用这个脚本插件
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
然后就可以调用脚本插件中的方法了
对象插件
对象插件就是实现了org.gradle.api.plugins接口的插件,对象插件可以分为内部插件和第三方插件。
内部插件
Gradle包中有大量的插件,比如我们经常用的java插件和c的插件,我们可以直接引入
apply plugin:'java'
apply plugin:'cpp'
三方插件
第三方的对象插件通常是jar文件,要想让构建脚本知道第三方插件的存在,需要使用buildscrip来设置。
在buildscrip中来定义插件所在的原始仓库和插件的依赖 ,再通过apply方法配置就可以了。Android Gradle插件也属于第三方插件,如果我们想引入Android Gradle插件,可以这么写:
buildscript {
repositories {
//配置仓库
google()
jcenter()
}
dependencies {
//配置插件依赖
classpath 'com.android.tools.build:gradle:3.5.3'
}
}
//然后就可以在需要的地方引入android 插件了
apply plugin: 'com.android.application'
自定义对象插件
自定义一个插件主要是实现 org.gradle.api.Plugin
Build script
这种方式直接在构建脚本中写插件代码,但是这种方式只能在本文件中使用,比如我在app的build.gradle中直接加入如下代码
class myPlugin implements Plugin<Project>{
@Override
void apply(Project project) {
println("myPlugin 执行了")
project.task("myTask"){
doLast {
println("myTask执行了")
}
}
}
}
然后引入在本文件定义的插件
apply plugin: myPlugin
这个就是直接在build.gradle 中实现了一个插件,在插件中定义了一个MyTask
任务,但是这个插件只能在本文件中使用,我们直接执行Mytask
任务./gradlew MyTask
> Task :mylibrary2:myTask
myTask执行了
执行阶段,task ':mylibrary2:myTask'耗时:1ms
这种方式实现的插件我们一般不使用,因为这种方式局限性太强,只能本Project,而其他的Project不能使用
buildSrc项目
buildSrc是Gradle默认的插件目录,编译Gradle的时候会自动识别这个目录,将其中的代码编译为插件,
- 首先先建立一个名为
buildSrc
的java Module,然后只保留build.gradle
和src/main
目录,其他全部删掉,注意名字一定是buildSrc
,不然会找不到插件 - 然后修改Gradle中的内容
apply plugin: 'groovy' //必须
apply plugin: 'maven'
dependencies {
implementation gradleApi() //必须
implementation localGroovy() //必须
//如果要使用android的API,需要引用这个,实现Transform的时候会用到
//implementation 'com.android.tools.build:gradle:3.3.0'
}
repositories {
google()
jcenter()
mavenCentral() //必须
}
//把项目入口设置为src/main/groovy
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
}
}
- 创建入口目录,在src/main下创建代码入口目录,如下:
- 然后实现插件代码
Text.groovy
,注意文件后缀为groovy
,文件要引入package com.renxh
package com.renxh
import org.gradle.api.Plugin
import org.gradle.api.Project
class Text implements Plugin<Project>{
@Override
void apply(Project project) {
println("执行自定义插件")
project.task("haha"){
doLast{
println("执行自定义插件 haha task")
}
}
}
}
- 接下来在
main
目录下创建resources
目录,在resources
目录下创建META-INF
目录,在META-INF
目录下创建gradle-plugins
目录,在gradle-plugins
目录下创建properties
文件 properties
文件可以自己命名,但是要以.properties
结尾,比如com.renxh.plugin.properties
- 最后需要在
properties
文件中指明我们实现插件的类implementation-class=com.renxh.Text
到目前为止我们的插件项目已经写完了,在module引入我们写的插件apply plugin:'com.renxh.plugin'
,然后执行插件的Task,./gradlew haha
输出
> Task :mylibrary:haha
执行自定义插件 haha task
执行阶段,task ':mylibrary:haha'耗时:0ms
这种形式的写法,在我们整个工程的module都可以使用,但也只是限制在本工程,其他工程不能使用
自定义module,上传maven
第二种写插件的方式他只能在本工程中使用,而其他的项目工程不能使用,有时候我们需要一个插件在多个工程中使用,这时候我们就需要把插件上传maven中
- 首先先建立一个
java module
,名字可以任意起,只保留build.gradle
和src/main
,其他文件都删除 - 修改Gradle中内容
apply plugin: 'groovy' //必须
apply plugin: 'maven' //要想发布到Maven,此插件必须使用
dependencies {
implementation gradleApi() //必须
implementation localGroovy() //必须
}
repositories {
mavenCentral() //必须
}
def group='com.renxh.cusplugin' //组
def version='2.0.0' //版本
def artifactId='myplugin' //唯一标示
//将插件打包上传到本地maven仓库
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = group
pom.artifactId = artifactId
pom.version = version
//指定本地maven的路径,在项目根目录下
repository(url: uri('../repos'))
}
}
}
相比buildSrc
方案,这个增加了Maven支持和uploadArchives
这样的Task,这个Task作用就是把本地插件打包上传到本地的maven仓库,这里../repos
表示项目根目录项下的repos,俩个.
回退俩次,回退到项目的根目录
在src/main
生成groovy
文件和生成properties
文件的步骤和buildSrc
方案一致的
编写插件
class CustomPlugin implements Plugin<Project>{
@Override
void apply(Project project) {
project.task("cusplugin"){
doLast{
println("cusplugin任务执行111")
}
}
}
}
然后执行./gradlew CusPlugin:uploadArchives
uploadArchives任务,然后就可以把repos目录布置到项目根目录了,如图:
repos
目录就是本地的Maven
仓库,com/renxh/cusplugin
就是脚本中指定的group
,myplugin
也是脚本中指定的模块名字,是一个唯一标识,1.0.0就是脚本中version
- 生成本地的maven仓库之后,就需要引用本地maven仓库中的插件了,首先需要在根目录的build.gralde中加入如下:
buildscript {
repositories {
google()
jcenter()
//引入本地仓库
maven {
url uri('./repos') //指定本地maven的路径,在项目根目录下
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
//引入本地仓库中的插件依赖
classpath 'com.renxh.cusplugin:myplugin:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
- classpath指定的路径格式,如下:
这三个参数都是在生成仓库的时候在build.gradle
脚本中配置的
classpath '[groupId]:[artifactId]:[version]'
- 配置完之后就可以在module中使用了
apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'
- 最后就可以执行插件中的任务
./gradlew app:cusplugin
> Task :app:cusplugin
cusplugin任务执行111
执行阶段,task ':app:cusplugin'耗时:0ms
插件的扩展 Extension
我们也可以在插件运行的时候,给插件配置参数,插件的Extension
就是用来把参数回传到插件中的
下面我就就给上面的插件添加Extension
首先建一个实体类,来接收参数
package com.renxh.cusplugin
class MyExtension {
String name;
int age;
}
然后去插件类中添加扩展
class CustomPlugin implements Plugin<Project>{
@Override
void apply(Project project) {
//添加扩展
project.extensions.add('myextension',MyExtension)
project.task("cusplugin"){
doLast{
println("cusplugin任务执行111")
MyExtension extension = project.myextension
//3.输出插件扩展属性
println ">>>>>> name: ${extension.name} age:${extension.age}"
}
}
}
}
- 通过project.extensions.add将自定以的实体类添加到扩展中,并起个名字
- 然后通过起的名字拿到扩展的实体类
- 最后拿到扩展中的属性
修改完之后重新上传maven
上传完之后,就可以在module中使用扩展实体类了
apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'
myextension{
name 'renxh'
age 27
}
最后执行插件中的task,./gradlew app:cusplugin
> Task :app:cusplugin
cusplugin任务执行111
>>>>>> name: renxh age:27
执行阶段,task ':app:cusplugin'耗时:2ms
参考