必须在settings.gradle中用dependencyResolutionManagement统一声明仓库,因其是Gradle 7.0+唯一能确保所有子模块解析依赖时使用一致仓库顺序的集中入口;subprojects方式无法管控解析阶段仓库可见性,易导致私有依赖解析失败、CI与本地构建不一致等问题。

必须在 settings.gradle(或 settings.gradle.kts)里用 dependencyResolutionManagement 块统一声明仓库,否则子模块会各自 fallback 到默认 Maven Central,且容易触发 build was configured to prefer settings repositories over project repositories 警告。
为什么不能只在根 build.gradle 里写 subprojects { repositories { ... } }
Gradle 7.0+ 引入了仓库作用域分层机制:settings 级仓库用于解析插件和项目依赖元数据,project 级仓库仅用于当前项目的依赖下载。如果只靠 subprojects 声明,Gradle 无法保证所有子模块在解析阶段就看到一致的仓库顺序,尤其当某个子模块自己又写了 repositories 时,就会发生覆盖或冲突。
常见错误现象:
- 部分子模块能下载私有依赖,部分报
Could not resolve - CI 构建失败但本地成功(因本地有缓存或 IDE 自动注入)
- Android 模块提示
Failed to resolve com.android.tools.build:gradle,即使插件版本正确
dependencyResolutionManagement 的标准写法(Kotlin DSL)
这是唯一推荐的集中式配置入口,适用于 Gradle 7.0+(含 Android Gradle Plugin 7.0+):
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
maven { url = uri("https://nexus.internal.company/repository/maven-public/") }
mavenCentral()
google() // Android 项目需要
}
}
关键点说明:
-
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)必须显式设置,否则 Gradle 默认允许子模块覆盖,失去统一管控意义 - 私有仓库务必放在公有仓库(
mavenCentral()、google())之前,依赖解析按顺序匹配 - 不要在任何
build.gradle里再写repositories—— 除非你明确要临时覆盖(比如某个子模块必须用特殊快照仓库)
Android 项目额外注意:pluginManagement 和 repositories 分开管
AGP 插件本身由 pluginManagement 解析,它不读取 dependencyResolutionManagement 中的仓库。所以必须单独配:
pluginManagement {
repositories {
maven { url = uri("https://nexus.internal.company/repository/maven-plugins/") }
gradlePluginPortal()
}
}
典型坑:
- 把 AGP 插件仓库错写进
dependencyResolutionManagement→ 插件找不到,报Plugin [id: 'com.android.application'] was not found - 私有插件仓库没配认证(
credentials),导致 CI 下载失败但无明确错误提示 -
gradlePluginPortal()放在私有仓库前面 → 可能拉到旧版插件,引发兼容性问题
离线构建和镜像切换的实际处理方式
企业环境中,硬编码 URL 或写死认证信息是高危操作。建议:
- 用环境变量控制镜像:
System.getenv("REPO_MIRROR_URLS")解析后动态替换url,避免提交敏感配置 - 离线模式(
--offline)下,Gradle 会跳过所有远程仓库,此时必须确保~/.gradle/caches/已预装所需依赖,否则直接失败 - 本地开发可加一个
mavenLocal()在最前,方便测试尚未发布到 Nexus 的快照包,但上线构建脚本中应移除
真正容易被忽略的是:仓库配置生效与否,不看构建是否成功,而要看 ./gradlew --dry-run dependencies 输出中每个模块实际使用的仓库列表 —— 这才是唯一可信依据。


















