Gradle插件扩展必须在Plugin.apply()开头注册,否则DSL配置块不生效;嵌套配置需用Provider+@Nested;字段须为Property类型并避免业务逻辑。

Gradle插件的扩展(Extension)不是“加个类就能用”,而是必须和 project.extensions 的契约对齐,否则配置块(如 myPlugin { ... })会被解析却完全不生效。
extension 实例必须在 project 初始化早期注册
很多人把 extensions.create() 放在 project.afterEvaluate 或自定义 task 里,这是错的——此时 DSL 闭包早已被跳过,不会绑定到任何实例上。
-
extensions.create("myPlugin", MyExtension.class)必须在Plugin.apply(Project)方法体最开始就调用 - 不能延迟到
afterEvaluate、tasks.register或任意构建逻辑之后 - Gradle 在解析
build.gradle时,会按顺序查找同名 extension;如果没提前注册,闭包直接丢弃,无报错也无日志
嵌套 extension 要用 Provider + nested() 声明
想支持类似 myPlugin { options { timeout = 5000 } } 这种结构?别手写 setter,得靠 Gradle 的类型安全嵌套机制。
- 主 extension 类中字段必须声明为
Provider<nestedoptions></nestedoptions>,不能是NestedOptions实例 - 注册时用
extensions.create("myPlugin", MyExtension.class).options = objects.newInstance(NestedOptions.class)是错的——破坏延迟求值 - 正确方式:在
MyExtension构造器里调用objects.domainObjectSet(NestedOptions.class)或用objects.newInstance()+nested()配合@Nested注解(Gradle 8.5+ 推荐) - 否则 Kotlin DSL 会报
Unresolved reference: options,Groovy DSL 会静默失败
配置块闭包绑定靠 ConfigurationAction,不是反射
你写的 myPlugin { outputDir = "out" } 不是靠 Groovy 的 setOutputDir() 反射调用生效的,而是 Gradle 内部通过 ConfigurationAction 把闭包委托给 extension 实例。
- extension 类所有可配置字段必须是 public、有 getter/setter(Kotlin 中需用
var+ 默认 getter/setter) - 字段类型要能被 Gradle 的
Property系统识别:优先用Property<string></string>、ListProperty<file></file>,而非原始类型 - 如果用了
@Input/@OutputDirectory等注解,必须搭配Provider使用,否则配置缓存(--configuration-cache)会失败 - 避免在 extension 类里做实际逻辑:它只负责承载配置,不负责执行;执行应交给 task 或
project.afterEvaluate中的 hook
最容易被忽略的一点:extension 类本身不能有无参构造函数以外的构造参数。Gradle 实例化它时不会传参,所有初始化逻辑(比如默认值)必须放在字段声明处或 ObjectsFactory 创建时完成。


















