AGP 到底干啥的?先聊聊它的角色
Android Gradle Plugin,圈里人都叫它 AGP。说白了,它就是 Android 工程和 Gradle 之间的那座桥。Gradle 是个通用构建系统,但 Android 需要的那些特殊操作——比如编译资源文件、生成 R 类、合并 manifest、签名打包——Gradle 自己可不会。AGP 就是在 Gradle 基础上,把这一整套 Android 构建逻辑封装成插件,让你在 build.gradle 里写几行配置就能把 APK 搞出来。
我个人习惯把 AGP 视为“构建管家”。你给它传递 compileSdk、minSdk、签名信息、混淆规则,它帮你协调资源处理、字节码转换、D8/R8 压缩,最后输出你想要的产物。没有它,你想想看,得手动调用 aapt2、dx/d8、apksigner——那画面太美我不敢看。
我记得刚转 Android 那会儿,有次升级 AGP 从 3.x 跳到 4.x,buildConfigField 行为变了,排查了一下午。从那以后我养成了个习惯:每次改 AGP 版本,一定先读一遍 release notes。
CI 是什么?跟我们有什么关系?
持续集成(Continuous Integration),字面意思是“不断合并代码并验证”。传统做法是“开发 -> 测试 -> 发布”线性走,往往是最后才跑出问题。CI 建议你每次提交代码都自动执行构建+测试,尽早发现冲突和缺陷。嗯,这里的关键词是“自动”和“每次”。
在 Android 项目里,CI 的核心动作通常包括:
- 拉代码、切分支
- 配置 SDK 和 AGP 版本(重要!)
- 执行
./gradlew assembleDebug或测试任务 - 运行单元测试、Lint、静态扫描
- 生成 APK/AAB 并归档或上报结果
我曾经在项目里遇到过这样的事:本地开发一直用 AGP 7.0,CI 机器上默认装的 Gradle 版本不兼容,构建直接挂了,整整耽误了一天。从那以后我就在 CI 脚本里显式声明 AGP 和 Gradle 版本号,并且用 gradle wrapper 锁定。
CI 流程长什么样?画给你看
一个典型的 Android CI 流程,从代码提交到产出报告,大致包含这几个阶段。下面这张图是我画的一个基础版本,你品品。
你仔细看,流程里专门放了一个“设置 AGP 版本”的节点。为什么要单独拎出来?因为 AGP 版本直接决定了 Gradle 构建的 Task 图和产物行为。不同的 AGP 版本哪怕只有小版本号之差,也可能导致 CI 构建结果不同。我建议你在 CI 配置文件里用变量控制 AGP 版本,而不是硬编码。
AGP 到底控制哪些 CI 环节?
我用一张表格帮你梳理 AGP 在 CI 各步骤中的具体影响,这样更直观。
| CI 环节 | AGP 的作用 | 常见坑点 |
|---|---|---|
| 源代码编译 | 调用 javac/kotlinc,生成 .class 文件 | AGP 4.x 后默认使用 D8,老项目可能还依赖 ProGuard |
| 资源打包 | aapt2 合并、编译资源,生成 R 类 | 资源 ID 非最终化时,多模块依赖可能编译失败 |
| 代码混淆 | 集成 R8(从 AGP 3.4+ 默认) | R8 与 ProGuard 规则不完全兼容,升级需检查 keep 规则 |
| 签名对齐 | zipalign + apksigner | AGP 7.0+ 使用 V2 签名默认,忘记配置签名文件导致 CI 产物不可安装 |
| 测试执行 | 生成 test APK,配置 instrumentation runner | 不同 AGP 版本对 UnitTest 和 InstrumentedTest 的分离策略不同 |
版本声明与 CI 环境
AGP 的版本声明通常在项目根 build.gradle 的 dependencies 块里:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.2.2'
}
}
同时记得通过 gradle wrapper 锁定 Gradle 自身版本。我曾经在 CI 上因为 wrapper 里写的是 gradle-7.5,但 AGP 8.2 要求最低 Gradle 8.0,结果直接报错 Minimum supported Gradle version is 8.0。嗯,所以建议你每次升级 AGP 都同步检查 Gradle 兼容性表。
./gradlew -v 先打印版本信息,再执行构建。这样一旦出问题,看日志就知道是 Gradle 还是 AGP 的锅。
CI 流程里 AGP 的“隐性影响”
你可能觉得 AGP 只是个插件,影响有限。其实它在 CI 中的渗透比表面深得多:
- Task 缓存: AGP 版本变化会导致缓存的 Task 失效,CI 的增量构建收益打折。
- DSL 变更: 比如
buildTypes里debuggable的默认值在不同 AGP 版本里有差异,直接改变产物行为。 - Lint 版本: 每个 AGP 内置的 lint 版本不同,导致 lint 检查结果不一致。
所以你在 CI 平台上维护多个项目时,强烈建议把 AGP 版本作为构建参数明确传递,而不是靠 CI 节点上预装的插件。我自己在 Jenkins Pipeline 里会用变量 ANDROID_GRADLE_PLUGIN_VERSION 来控制,每个项目独立配置。
@Keep 注解失效,R8 把不该混淆的类给干掉了。AGP 7.1 改了 R8 的默认配置,keep 规则要额外添加 -keepattributes *Annotation*。从那以后每次升级我都要跑一遍回归测试才放心。
好了,AGP 的定位和它在 CI 中的基础角色,我想你应该心里有数了。接下来我们会从具体版本开始逐一拆解,但那是后话。