第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 也被内部仓库代理,则无需单独声明
}
常见错误:
• 将 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 缓存 内部代理仓库 (Nexus / Artifactory) Maven Central JitPack ⚠ 认证/令牌注入点 Basic Auth 或 Bearer 通过 gradle.properties 或环境变量注入 仓库优先级 ① 本地缓存 ② 内部代理 ③ 远程

上图展示了标准解析路径:开发构建机首先命中 本地 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 属性,兼顾安全与可维护性。