最直接安全的做法是只在目标子模块的build.gradle中apply插件;插件默认作用域为当前Project,不跨模块传播;根项目中误用会导致构建失败。

只在某个子模块的 build.gradle 里写 apply plugin
这是最直接、最安全的做法。Gradle 的插件作用域默认就是当前 Project 实例,不会跨模块传播。只要你不把它写在根项目的 build.gradle 或 settings.gradle 里,它就不会影响其他模块。
常见错误现象:在根项目 build.gradle 中写了 apply plugin: 'com.android.application' —— 这会导致构建失败,因为根项目通常不是 application 类型。
- 正确做法:只在
:app模块的build.gradle里写plugins { id 'com.android.application' } - 如果用旧式语法,写
apply plugin: 'com.android.application'也只对当前文件生效 - 注意
plugins { ... }块必须是文件最顶层的 DSL,不能嵌套在subprojects或allprojects里(否则会报错Plugin with id 'xxx' not found)
subprojects 和 allprojects 中按条件过滤模块
当你需要批量配置、但又想排除某些模块时,不能靠“不写”来控制,得显式判断模块名或路径。
使用场景:给所有业务模块加 jacoco 插件,但跳过 :buildSrc、:common 等基础库模块。
- 在根项目
build.gradle中用subprojects+if判断:subprojects { if (name != 'buildSrc' && !name.startsWith('common')) { apply plugin: 'org.gradle.testing.jacoco' } } -
allprojects会包含根项目本身,一般不用;subprojects更精准,只遍历settings.gradle中include的子模块 - Kotlin DSL 写法类似,但注意
apply(plugin = "...")是函数调用,不是 DSL 块
用 afterEvaluate 延迟判断模块类型再应用
有些插件(比如 com.android.application)要求项目已配置好 android 块才能安全应用。如果模块还没完成解析就硬 apply,会抛 Could not get unknown property 'android'。
这时候不能靠名字过滤,得靠实际配置是否存在。
- 示例:只为真正有
android配置的模块启用 Android 插件相关逻辑subprojects { afterEvaluate { project -> if (project.extensions.findByName('android') != null) { project.apply plugin: 'com.github.ksoichiro.android-gradle-plugin' } } } -
afterEvaluate确保该模块的build.gradle已解析完毕,属性和扩展都可访问 - 注意:这种写法容易掩盖配置顺序问题,仅在必要时使用;优先推荐第一种“只在目标模块写”的方式
自定义插件里用 project.path 控制作用范围
如果你在 buildSrc 或独立插件项目中开发二进制插件,可以在 apply(Project) 方法里主动检查当前项目路径,决定是否执行后续逻辑。
这比在外部脚本里一堆 if 更干净,也更利于复用。
- 示例:
class MyCustomPlugin implements Plugin<Project> { void apply(Project project) { // 只对 :feature:login 模块生效 if (project.path == ':feature:login') { project.task('generateLoginConfig') { /* ... */ } } // 或按路径前缀匹配 if (project.path.startsWith(':module:')) { project.extensions.create('myconf', MyExtension) } } } -
project.path返回完整路径如:app、:library:network,比project.name更可靠(多个同名模块时) - 避免在插件里调用
project.subprojects,那会污染其他模块,违背“指定模块”的初衷
最容易被忽略的一点:插件的 apply 行为发生在项目配置阶段,而模块之间的依赖关系(implementation project(':lib'))是在执行阶段才真正起作用的。所以哪怕你只给 :app 应用了某个插件,它也不会自动把行为“传染”给它依赖的 :lib —— 除非你在插件里手动遍历了 project.configurations 或 project.dependencies 并做了额外操作。


















