Gradle插件开发
看完本文,你会收获:
- 可以自定义一个属于自己的【Gradle插件】!!
背景
笔者HB实习,mentor最近分配给我的任务是:
编写一个【Gradle插件】
- 场景:A、B两个工程,其中A工程依赖了B中的某些方法/类/属性等,B修改后更新版本,但A工程的依赖并未更新,导致工程build通过但run失败
- 用途:检测工程之间相互依赖问题(在.class文件转化.dex之间检测依赖问题,若存在,则build无法通过)
一、概述
1.1、Gradle
- Gradle 是一款Google 推出的基于 JVM、通用灵活的项目构建工具,支持 Maven,JCenter 多种第三方仓库;支持传递性依赖管理、废弃了繁杂的xml 文件,转而使用简洁的、支持多种语言(例如:java、groovy 等)的 build 脚本文件。
二、Gradle插件
2.1、使用插件的原因
- 促进代码重用、减少功能类似代码编写、提升工作效率
- 促进项目更高程度的模块化、自动化、便捷化
- 可插拔式的的扩展项目的功能
2.2、分类
2.2.1、脚本插件
- 脚本插件的本质就是一个脚本文件,使用脚本插件时通过apply from:将脚本加载进来就可以了,后面的脚本文件可以是本地的也可以是网络上的脚本文件,下面定义一段脚本,我们在 build.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"
2.2.2、对象插件(核心)
二进制插件[对象插件]就是实现了 org.gradle.api.Plugin 接口的插件,每个 Java Gradle 插件都有一个 plugin id。
1、内部插件
1 、可通过如下方式使用一个 Java 插件:
apply plugin : 'java' //map具名参数方式或者:
2、也可以使用闭包作为project.apply方法的一个参数
apply{
plugin 'java'
}
- 通过上述代码就将 Java 插件应用到我们的项目中了,对于 Gradle 自带的核心插件都有唯一的 plugin id,其中 java 是Java 插件的 plugin id,这个 plugin id 必须是唯一的,可使用应用包名来保证 plugin id 的唯一性。这里的 java 对应的具体类型是 org.gradle.api.plugins.JavaPlugin,所以可以使用如下方式使用 Java 插件:
//使用方式1:Map具名参数,全类名
apply plugin:org.gradle.api.plugins.JavaPlugin
//使用方式2 apply plugin:JavaPlugin
apply plugin: 'java'
//使用方式3:插件的id
2、第三方插件
- 如果是使用第三方发布的二进制插件,一般需要配置对应的仓库和类路径
//使用传统的应用方式
buildscript {
ext {
springBootVersion = "2.3.3.RELEASE"
}
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
jcenter()
}
// 此处先引入插件
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
//再应用插件
apply plugin: 'org.springframework.boot'
//社区插件,需要事先引入,不必写版本号,但是如果是第三方插件已经被托管在 https://plugins.gradle.org/ 网站上,就可以不用在 buildscript 里配置 classpath
依赖了,直接使用新出的 plugins DSL 的方式引用,案例如下: 使 用 plugins DSL 方 式
plugins {
id 'org.springframework.boot' version '2.4.1'
}
注意:
- 如果使用老式插件方式buildscript{}要放在build.gradle 文件的最前面,而新式plugins{}没有该限制。
- 托管在网站gradle 插件官网的第三方插件有两种使用方式,一是传统的buildscript 方式,一种是 plugins DSL 方式 。
3、自定义插件【本文重点】,下面详细
三、Gradle自定义插件【重点】
接下来,直接上才艺
1、新建module,选择Java library
2、进行配置
- 1、在/main目录下新建resources/META-INF/gradle-plugins目录(必须是这个格式!!)
- 2、新建一个文件: 【com.example.myPlugin】.properties
写入:implementation-class=com.example.myPlugin.MyPlugin
3、进入myPlugin的build.gradle下,加入依赖,然后同步一下(sync)
plugins {
id 'maven-publish' //用于上传,之后每一步都要publish一次!!!
id 'java-library'
id 'groovy'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "com.android.tools.build:gradle:3.5.0"
implementation gradleApi()
}
//定义Maven仓库信息
def MAVEN_GROUP_ID = "com.example.myPlugin"
def MAVEN_ARTIFACT_ID = "myPlugin"
def MAVEN_VERSION = "1.0"
publishing {
publications {
java(MavenPublication) {
from components.java
groupId = MAVEN_GROUP_ID
artifactId = MAVEN_ARTIFACT_ID
version = MAVEN_VERSION
}
}
repositories {
mavenLocal() //上传至本地的maven仓库,也可以到远程库
}
}
4、到root目录的build.gradle下,导入依赖,再次同步一下(sync)
dependencies {
.....
classpath 'com.example.myPlugin:myPlugin:1.0'
.....
}
5、到要引入本插件的工程的build.gradle下(笔者这里是一个android项目,就到app目录下),再次同步一下(sync)
plugins {
......
id 'com.example.myPlugin'
......
}
6、编写插件的具体逻辑
这个部分就任意发挥的,极尽你的想象
public class NewPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
System.out.println("具体功能");
// to do sth.....
}
四、写在最后
- 笔者最近在准备秋招,投了不下50份简历了,全部石沉大海,呜呜呜~。
- 随后可能会更出来第二期,Gradle自定义插件 + Transform API + Java ASM整合。
- 但是大家不要因为大环境不好就破罐子破摔,不要摆烂!不要摆烂!不要摆烂!大家加油,共勉!!!