14、自定义插件开发(一):创建插件项目、实现Plugin接口、注册Task、发布到本地仓库
说实话,Gradle 的插件机制是我最喜欢它的地方之一。你想想看,如果每次都要在几十个模块里重复写同样的配置,那得多痛苦?我早期带团队的时候,就吃过这个亏——项目一多,build.gradle 文件里全是复制粘贴的代码,改个版本号得全局搜索替换,那叫一个酸爽。
后来我下定决心,把那些重复的逻辑抽成自定义插件。嗯,从那以后,维护成本直线下降。今天我们就来走一遍自定义插件开发的全流程,从零开始创建一个插件项目,实现 Plugin 接口,注册 Task,最后发布到本地仓库。
为什么需要自定义插件?
说白了,Gradle 插件就是一段可复用的构建逻辑。你可以把它理解成一个「构建工具箱」,里面装好了各种 Task、配置、扩展点。别人用的时候,只需要 apply 一下,就能拿到整套能力。
我在项目中遇到过最典型的场景:公司内部有统一的代码规范检查、统一的版本号管理、统一的发布流程。如果每个子项目都自己写一遍,不仅累,还容易出错。抽成插件后,一行 apply plugin: 'com.company.standard' 就搞定了。
核心价值:插件 = 封装 + 复用 + 标准化。一次开发,到处使用。
第一步:创建插件项目结构
Gradle 插件本质上是一个 JVM 项目,你可以用 Java、Groovy 或 Kotlin 来写。我个人习惯用 Java,因为团队里 Java 开发者最多,上手没门槛。
先创建一个标准的 Gradle 项目,目录结构如下:
my-plugin/
├── build.gradle
├── settings.gradle
├── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── MyPlugin.java
│ └── resources/
│ └── META-INF/
│ └── gradle-plugins/
│ └── com.example.myplugin.properties
注意那个 META-INF/gradle-plugins/ 目录下的 properties 文件。这个文件是 Gradle 识别插件的关键,文件名就是你的插件 ID。比如 com.example.myplugin.properties,内容就一行:
implementation-class=com.example.MyPlugin
这行配置告诉 Gradle:当用户 apply 插件 com.example.myplugin 时,实际执行的是 com.example.MyPlugin 这个类。
注意:properties 文件的路径和文件名必须严格遵循 META-INF/gradle-plugins/{插件ID}.properties 的格式。我曾经因为少写了一个字母,导致插件死活加载不上,排查了半天才发现是文件名拼错了。
第二步:编写 build.gradle
插件项目本身也需要构建配置。我们需要引入 Gradle 的插件开发 API:
plugins {
id 'java-gradle-plugin'
id 'maven-publish'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
implementation gradleApi()
// 如果你需要其他依赖,比如解析 JSON,可以加在这里
// implementation 'com.google.code.gson:gson:2.10.1'
}
java-gradle-plugin 这个插件会自动帮我们生成一些必要的配置,比如自动注册插件描述文件。而 maven-publish 则是用来发布插件的,后面会用到。
第三步:实现 Plugin 接口
现在来写核心代码。实现 org.gradle.api.Plugin 接口,只需要重写一个 apply 方法:
package com.example;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
public class MyPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
System.out.println("Hello from MyPlugin! 项目名称: " + project.getName());
// 在这里注册 Task、添加扩展、配置依赖等
project.getTasks().register("myTask", MyTask.class, task -> {
task.setDescription("这是一个自定义 Task");
task.setGroup("MyPlugin");
});
}
}
你看,apply 方法会在插件被应用时自动调用。参数 Project 就是当前应用插件的项目对象,通过它可以访问项目的所有配置和 Task。
这里我注册了一个名为 myTask 的 Task,类型是 MyTask。接下来我们创建这个 Task 类。
第四步:创建自定义 Task
Task 类需要继承 DefaultTask,并用 @TaskAction 注解标记要执行的方法:
package com.example;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.TaskAction;
public class MyTask extends DefaultTask {
@TaskAction
public void doSomething() {
System.out.println("执行 myTask...");
System.out.println("当前项目: " + getProject().getName());
// 这里可以写任何构建逻辑
// 比如复制文件、执行命令、生成报告等
}
}
嗯,这里要注意:Task 类里的属性可以用 @Input、@Output 等注解来声明输入输出,这样 Gradle 就能做增量构建。不过那是下一章的内容,今天我们先跑通基本流程。
第五步:发布到本地仓库
插件写好了,怎么给别人用?最简单的方式就是发布到本地 Maven 仓库。在 build.gradle 中配置发布信息:
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
repositories {
maven {
// 发布到本地仓库,默认路径是 ~/.m2/repository
url = uri(layout.buildDirectory.dir("repo"))
// 也可以发布到本地文件系统的其他位置
// url = uri("file:///Users/me/local-repo")
}
}
}
然后执行发布命令:
./gradlew publish
执行成功后,你会在 build/repo 目录下看到生成的 jar 包和 pom 文件。结构大概是这样的:
build/repo/
└── com/
└── example/
└── my-plugin/
└── 1.0.0/
├── my-plugin-1.0.0.jar
├── my-plugin-1.0.0.pom
└── ...
小技巧:如果你想让其他项目直接引用本地仓库的插件,可以在其他项目的 settings.gradle 或 build.gradle 中添加仓库地址:
pluginManagement {
repositories {
maven {
url = uri("file:///path/to/my-plugin/build/repo")
}
gradlePluginPortal()
mavenCentral()
}
}
第六步:在其他项目中使用插件
发布完成后,就可以在其他项目中应用这个插件了。在目标项目的 build.gradle 中:
plugins {
id 'com.example.myplugin' version '1.0.0'
}
然后执行 ./gradlew myTask,就能看到控制台输出:
Hello from MyPlugin! 项目名称: my-app
执行 myTask...
当前项目: my-app
看到这个输出,说明插件已经成功工作了。
核心流程总结
整个开发流程可以用下面这张图来概括:
常见问题与避坑指南
- 插件 ID 冲突:插件 ID 最好是反向域名格式,比如
com.company.plugin。我曾经见过有人用myplugin这种简单名字,结果跟其他库冲突了,排查起来很麻烦。 - properties 文件位置不对:必须放在
src/main/resources/META-INF/gradle-plugins/下,文件名必须和插件 ID 完全一致。少一个字母都不行。 - 发布后找不到插件:检查一下其他项目的
pluginManagement仓库配置是否指向了正确的本地路径。我习惯把本地仓库路径写成一个变量,方便切换。 - Task 不执行:确认 Task 类上有
@TaskAction注解,并且方法签名正确(无参数,返回 void)。
核心要点回顾:
- 插件项目需要
java-gradle-plugin和maven-publish两个插件 - 实现
Plugin<Project>接口,在apply方法中注册 Task - Task 类继承
DefaultTask,用@TaskAction标记执行方法 - 通过
META-INF/gradle-plugins/下的 properties 文件声明插件实现类 - 使用
./gradlew publish发布到本地仓库
好了,到这里你已经掌握了自定义插件开发的基本功。下一章我们会深入插件的扩展点,让用户可以在 build.gradle 中配置参数,实现更灵活的构建逻辑。不过那是后话了,今天先把基础打牢。
公众号:蓝海资料掘金营,微信deep3321