Gradle插件本质是实现Plugin接口的类,apply()方法接收Project对象并操作其任务、配置等;需严格匹配泛型、无参构造、正确META-INF配置或buildSrc规范。

Plugin 接口实现类必须继承 Plugin<project></project>
Gradle 插件的本质就是一个实现了 Plugin 接口的类,且泛型必须是 Project(不能是 Object 或省略)。否则 Gradle 在加载时会直接抛出 ClassCastException 或静默失败——尤其在 Kotlin 中容易因类型推导错误写成 Plugin 或 Plugin<any></any>,导致 apply() 方法不被识别。
常见错误现象:
- 插件类编译通过,但
apply plugin: 'xxx'后无任何效果,任务没注册、扩展没暴露 - 使用
plugins { id 'xxx' }时提示Could not find plugin with id 'xxx',即使META-INF/gradle-plugins/xxx.properties文件存在
正确写法(Kotlin 示例):
class DemoPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("hello") {
it.doLast { println("Hello from DemoPlugin") }
}
}
}
META-INF/gradle-plugins/ 下的 properties 文件名和内容必须严格匹配
二进制插件要被 plugins { id 'xxx' } 识别,必须在 JAR 的 META-INF/gradle-plugins/ 目录下放置一个以插件 ID 命名的 .properties 文件,且内容只能是 implementation-class=全限定类名,不能有空格、注释或额外换行。
容易踩的坑:
- 文件名写成
demo-plugin.properties,但plugins { id 'demo.plugin' }—— ID 和文件名必须完全一致(包括点号、连字符) - 内容写成
implementation-class: com.example.DemoPlugin(用了冒号而非等号) - 类名拼错,比如
com.example.demo.DemoPlguin(少个 i),运行时抛ClassNotFoundException - 用 Groovy 写插件却把
.properties放在src/main/resources下,但未配置processResources任务将其复制进 JAR
buildSrc 方式下不需要 META-INF,但包路径和类名仍需规范
放在 rootProjectDir/buildSrc/src/main/kotlin/ 下的插件类,Gradle 会自动编译并注入 classpath,此时不走 META-INF 查找逻辑,而是靠类路径反射加载。但仍有硬性约束:
- 类必须是 public(Kotlin 默认 public,Groovy 类需显式加
public修饰) - 不能是匿名类、局部类或非静态内部类(否则
apply plugin: DemoPlugin::class会报NoClassDefFoundError) - 若用
apply plugin: 'com.example.demo'语法(非plugins {}块),仍需META-INF;而buildSrc中推荐直接用类引用:apply plugin: DemoPlugin
例如,在 buildSrc/src/main/kotlin/com/example/DemoPlugin.kt 中定义类后,主项目 build.gradle.kts 可直接写:
apply(plugin = com.example.DemoPlugin::class)
Standalone 工程发布时,java-gradle-plugin 插件会自动处理 META-INF
如果你用独立模块开发插件(非 buildSrc),务必在插件工程的 build.gradle 中启用 java-gradle-plugin:
plugins {
`java-gradle-plugin`
}
gradlePlugin {
plugins {
register("demoPlugin") {
id = "com.example.demo"
implementationClass = "com.example.DemoPlugin"
}
}
}
这个插件会自动在 JAR 中生成正确的 META-INF/gradle-plugins/com.example.demo.properties,避免手动生成出错。但注意:implementationClass 必须是字符串字面量,不能是类引用表达式,否则打包时找不到类。
最容易被忽略的一点:插件类的构造函数必须是无参的。Gradle 通过反射调用 Class.newInstance()(旧版)或 Constructor.newInstance()(新版),任何带参构造都会导致 InstantiationException。


















