第3章:公司内部 Maven 仓库与代理仓库选型
在 AGP 版本升级及离线依赖缓存管理中,引入公司内部 Maven 仓库(或代理仓库)是减少外网依赖、统一版本管控、加速构建的核心手段。本章将围绕 Nexus、Artifactory、JitPack 三款主流方案进行离线缓存配置对比,并详解仓库优先级配置、认证与令牌注入的实战细节。
3.1 主流仓库对比总览
| 特性 | Nexus(Sonatype) | Artifactory(JFrog) | JitPack |
|---|---|---|---|
| 许可证 | 社区版免费 / Pro 付费 | OSS 免费 / 企业版付费 | 开源免费(SaaS托管,可自建) |
| 离线缓存机制 | 代理仓库缓存(远程组件第一次下载后永久保留) | 同 Nexus,支持复制/远程仓库智能缓存 | 需要 Git 仓库地址触发构建;缓存是以构建产物形式保存 |
| 仓库优先级控制 | 支持 group 仓库(按顺序合并多个仓库) | 支持 virtual 仓库(类似 group ) | 自行配置 Gradle repositories 顺序 |
| 认证方式 | Basic Auth / Bearer / 匿名 | Basic Auth / / 匿名 | 通常无需认证(公开仓库);私有需 |
| AGP 兼容性 | 良好(支持 Maven, Gradle Plugin Portal) | 优秀(支持所有 Maven/Gradle 协议) | 受限(仅支持 GitHub/GitLab 仓库) |
| 部署复杂度 | 中等(Java 应用,需配置 Prox/Blob) | 较复杂(系统要求高,支持 Artifactory Edge) | 简单(SaaS 无需部署,自建需 Docker) |
| 推荐场景 | 长期维护的内部仓库,需稳定代理缓存 | 大规模团队,需丰富元数据管理 | 私有依赖按需构建,临时仓库 |
选型建议: 大多数 Android 团队选择 Nexus Repository 3 (OSS) 作为内部代理仓库,安装简便、社区活跃、离线缓存策略成熟;若已有 JFrog 生态(如 DevOps 平台集成),则 Artifactory 是更优选择。JitPack 更适合“只读”的 GitHub 公共库缓存,不建议作为主力内部仓库。
3.2 仓库优先级配置
Gradle 解析依赖时按照 repositories 块中声明的顺序依次查找。在离线环境下,必须保证 本地缓存 > 内部代理仓库 > 远程仓库 的查找顺序,否则会导致大量网络请求。
// build.gradle (项目级)
repositories {
// 1. 本地 Maven 缓存(离线场景必备)
mavenLocal()
// 2. 内部代理仓库(Nexus 或 Artifactory)
maven {
url = uri("https://nexus.company.com/repository/maven-public/")
// 认证注入见 3.3 节
credentials {
username = project.findProperty("nexusUser") ?: ""
password = project.findProperty("nexusPass") ?: ""
}
}
// 3. 远程 Maven Central(被代理仓库已缓存时不会触发)
mavenCentral()
// 可选:如果 JitPack 也被内部仓库代理,则无需单独声明
}
常见错误:
• 将
• 内部仓库 URL 拼写错误或协议不匹配(如 https 写成 http)会导致认证握手失败。
• 将
mavenCentral() 或 google() 写在内部仓库之前,会导致 Gradle 跳过内部缓存,直接访问外网(离线时构建失败)。• 内部仓库 URL 拼写错误或协议不匹配(如 https 写成 http)会导致认证握手失败。
3.3 认证与令牌注入
内部仓库常要求基本认证或 。推荐使用 Gradle 属性 + 环境变量 注入,避免敏感信息硬编码到版本控制。
方式一:gradle.properties + 本地文件
# ~/.gradle/gradle.properties
nexusUser=android-builder
nexusPass=YOUR_PASSWORD_OR_
方式二:环境变量 + 系统属性
export NEXUS_USER=android-builder
export NEXUS_PASS=_xxx123
# 在 build.gradle 中读取:
nexusUser = System.getenv("NEXUS_USER") ?: ""
nexusPass = System.getenv("NEXUS_PASS") ?: ""
方式三:Bearer (Nexus / Artifactory 均支持)
maven {
url = uri("https://nexus.company.com/repository/maven-public/")
authentication {
create<BasicAuthentication>("basic")
}
credentials {
username = "" // Nexus 固定用户名 ""
password = "your-api-" // 实际 值
}
}
安全最佳实践: 令牌应定期轮换,并在 CI/CD 系统中使用 Secret 变量注入,避免明文写入 gradle.properties 提交到仓库。Nexus 支持为每个仓库设置独立的访问 ,建议按项目组隔离。
3.4 离线缓存工作流(SVG 拓扑)
上图展示了标准解析路径:开发构建机首先命中 本地 Gradle 缓存(~/.gradle/caches/),若未命中则请求 内部代理仓库,内部仓库缓存未命中则回源到 远程 Maven Central / JitPack。认证令牌仅在内部代理仓库处注入,远程仓库通常为公开只读。
3.5 调试命令与常见错误排查
调试命令
# 查看 Gradle 依赖解析日志(详细输出)
./gradlew build --info | grep "Repository" | grep "from"
# Nexus 中查看缓存是否命中(REST API)
curl -u username:password -X GET "https://nexus.company.com/service/rest/v1/search?repository=maven-public&name=com.android.tools.build:gradle"
# Artifactory 缓存状态
curl -u username:password -X GET "https://artifactory.company.com/api/storage/libs-releases/com/android/tools/build/gradle/7.4.2/gradle-7.4.2.pom"
常见错误及修复
| 错误表现 | 原因 | 解决方案 |
|---|---|---|
| Could not resolve dependency … | 仓库顺序导致直连远程失败(离线) | 调整 repositories 顺序,将内部仓库放在远程之前 |
| 401 Unauthorized | 认证凭据缺失或过期 | 检查 gradle.properties 中的用户名/密码; 是否被撤销 |
| 409 Conflict (Nexus) | 代理仓库配置了只读权限,写入了重复组件 | 使用“允许 redeploy”策略或调整仓库类型为 hosted |
| 资源文件在本地找到了,但构建仍失败 | 本地缓存校验失败(SHA1 不匹配) | 清除本地缓存:rm -rf ~/.gradle/caches/modules-2 并重新构建 |
3.6 性能与稳定性优化
- Nexus 配置建议: 开启“智能搜索”索引,设置合理的过期策略(如 7 天未访问仍保留,避免频繁回源)。
- 多仓库镜像: 将
google()、mavenCentral()、jcenter()(已下线)等全部映射到同一个内部仓库组,减少 Gradle 多仓库串行查询时间。 - 预缓存(预热): 在新环境(如 CI 节点)构建前,运行
./gradlew dependencies --offline强制下载所有依赖;若内部代理已缓存,速度可提升 10~50 倍。 - 证书问题: 内部仓库使用自签名证书时,需将证书导入 Gradle 的信任库或 Java cacerts,否则
SSLHandshakeException会导致构建中断。
关键总结:
• Nexus 是离线缓存管理的“首选武器”,与 Gradle 生态完美兼容。
• 仓库优先级必须显式配置(本地 → 内部 → 远程),否则离线时构建寸步难行。
• 认证令牌注入推荐使用环境变量 + Gradle 属性,兼顾安全与可维护性。
• Nexus 是离线缓存管理的“首选武器”,与 Gradle 生态完美兼容。
• 仓库优先级必须显式配置(本地 → 内部 → 远程),否则离线时构建寸步难行。
• 认证令牌注入推荐使用环境变量 + Gradle 属性,兼顾安全与可维护性。