子模块依赖必须在build.gradle中用project()显式声明,仅include到settings.gradle中不足以建立依赖关系;路径需严格匹配、避免循环依赖,并注意sourceSets覆盖导致的源码不可见问题。

子模块依赖必须在 build.gradle 里用 project() 声明
Gradle 不会自动识别子模块之间的调用关系。即使你在 settings.gradle 里通过 include 把模块都加进来了,也得在每个子模块自己的 build.gradle 文件中显式声明它依赖谁。
常见错误是只改了 settings.gradle,却忘了在 dependencies 块里写 implementation project(':xxx'),结果编译时报 package xxx does not exist 或找不到类。
-
implementation project(':shared')是最常用写法,表示当前模块编译和运行都需要shared模块产出的代码 - 如果当前模块的 public API 里直接暴露了
shared中的类型(比如方法返回值、参数类型),就得换成api project(':shared'),否则上层模块编译会失败 - 不能写成
implementation 'com.example:shared:1.0'—— 这是远程坐标语法,对本地子模块无效
settings.gradle 必须先 include 才能被 project() 引用
project(':xxx') 的路径名必须和 settings.gradle 里 include 的字符串完全一致,包括大小写和斜杠方向。比如你写了 include 'utils',那依赖就必须写 project(':utils'),而不是 project(':Utils') 或 project('utils')。
- 路径前缀的冒号
:表示从根项目开始找,project(':api')和project(':core:api')是不同层级 - 如果子模块在嵌套目录下(如
core/network),include要写成include 'core:network',对应依赖写project(':core:network') - IDEA 有时会缓存旧的
settings.gradle内容,改完记得点Reload project,否则project()会报Project with path ':xxx' could not be found
避免循环依赖:Gradle 会直接拒绝构建
如果你在 A 的 build.gradle 里写 implementation project(':B'),又在 B 里写 implementation project(':A'),Gradle 在配置阶段就会报错:Circular dependency between projects。这不是警告,是构建中断。
- 这种错误往往藏得深:A → B → C → A,链路一长就容易漏看
- 可以用
./gradlew dependencies --configuration compileClasspath查看依赖树,快速定位闭环 - 解法不是“绕开检查”,而是重构——把公共逻辑抽到第三个模块(如
:common),让 A 和 B 都依赖它
跨模块资源或源码不可见?检查 sourceSets 是否被意外覆盖
有时候明明写了 implementation project(':shared'),但依然访问不到 shared/src/main/resources 下的配置文件,或者 shared/src/main/java 里的类提示“cannot resolve symbol”。问题常出在子模块自己重写了 sourceSets,导致 Gradle 没把依赖模块的源码路径加入 classpath。
- 默认情况下,
project()依赖只传递编译产物(jar/aar),不传递源码目录;但 IDE(如 IDEA)通常会自动映射源码,供跳转和调试 - 如果手动配置了
sourceSets.main.java.srcDirs = ['src/custom'],却没保留原来的路径,就会丢掉project()带来的源码可见性 - 安全做法是用
srcDirs +=追加,而不是直接赋值覆盖


















