Gradle子模块间不自动传递build输出文件,project(':lib')依赖的是源码而非jar包;需用artifact+configuration机制显式声明产物依赖,如implementation(project(path: ':B', configuration: 'dist'))。

Gradle子模块之间不能自动传递生成的文件(比如 build/libs/*.jar),除非你显式配置了项目依赖或产物发布逻辑。默认情况下,每个子模块的 build/ 目录是隔离的,其他模块看不到、也用不到其中的输出。
为什么 implementation project(':lib') 不等于“把 lib 的 jar 拿过来”
这是最容易误解的一点:project(':lib') 依赖不是在编译时复制 lib/build/libs/lib-1.0.jar,而是让 Gradle 把 lib 模块的源码、资源、compileClasspath 和 runtimeClasspath 全部纳入当前构建上下文。也就是说:
- 它直接编译
lib/src/main/java,不走 jar 打包再解压流程 -
lib的build/下任何文件(包括 jar、war、resources)都不会被其他模块“看到”或“读取” - 如果你在
app模块里写代码去读lib/build/libs/lib.jar,会失败——路径不存在,且 Gradle 不保证该 jar 已生成
想让子模块 A 用子模块 B 生成的某个文件,必须明确声明产物类型
常见需求如:B 模块打包成一个 .jar 或 .zip,A 模块在构建时解压它、读取配置、或作为工具执行。这时不能靠 project(),得用 artifact + configuration 机制:
- 在 B 的
build.gradle中定义一个自定义 configuration,比如archives或新建dist - 把目标文件(如
build/distributions/mytool.zip)通过artifacts { archives file(...) }注册进去 - 在 A 的
build.gradle中用implementation files(project(':B').tasks.named('assemble').get().outputs.files)是错的;正确做法是声明对 B 的distconfiguration 的依赖:implementation(project(path: ':B', configuration: 'dist')) - 然后在 A 的 task 中,通过
configurations.dist.singleFile获取该文件路径
Android 场景下特别注意:aar 不是 jar,且资源不会自动暴露
如果你的子模块是 android-library 类型,它默认产出 .aar,而 implementation project(':lib') 只会把 classes.jar 和 res/、AndroidManifest.xml 等合并进主模块的构建流程,但不会让你在代码里直接访问 lib/build/outputs/aar/lib-debug.aar 这个文件本身。
- 如果 A 模块需要在构建时解析 B 的 aar(比如做插件扫描),得用
afterEvaluate+configurations.apiElements.artifacts,且要确认 B 启用了publishing插件 - 更稳妥的做法是让 B 在
build.gradle里加一句android.libraryVariants.all { variant -> variant.assembleProvider.configure { finalizedBy 'copyAarToDir' } },再定义一个 copy task 把 aar 输出到固定路径,A 再去读那个路径 - 别依赖 IDE 自动刷新后的
build/结构——命令行构建和 IDE 构建的输出时机可能不一致
真正难的不是怎么写那几行配置,而是想清楚:你到底是要复用代码逻辑(用 project())、还是消费构建产物(用 configuration + artifact)、还是运行时加载文件(那就得自己写 copy task 并控制执行顺序)。三者混用,不出问题才怪。


















