第1章 AGP构建流程与增量编译原理

AGP(Android Gradle Plugin)的构建过程本质上是 Gradle Task 的有向无环图(DAG)调度。理解构建阶段划分、增量编译触发条件以及 Task 缓存命中机制,是后续优化编译速度、适配不同 AGP 版本的基石。

1.1 Gradle 构建三大阶段

Gradle 的每一次构建都严格遵循三个阶段,AGP 在此基础上注入 Android 专有 Task。

阶段核心行为AGP 注入的任务示例
初始化(Initialization)解析 settings.gradle,确定参与构建的 Project 列表无
配置(Configuration)执行每个 Project 的 build.gradle,生成 Task 依赖图 DAGandroid.applicationVariants, compileSdk 配置
执行(Execution)按 DAG 顺序执行 Task,生成产物mergeDebugResources, compileDebugKotlin
关键结论:配置阶段越短,增量编译越敏感。每次配置阶段都会重新计算所有 Task 的输入/输出快照,即使后续执行阶段可能跳过。

1.2 增量编译触发条件

AGP 的增量编译并非所有 Task 默认启用,它只对声明了 @Incremental 注解的 Task 生效。触发条件分为三类:

  1. 源文件变更:Java/Kotlin 源文件、资源文件、AndroidManifest.xml 等被修改、新增或删除。
  2. 构建配置变更:build.gradle 中依赖版本、compileSdk、minSdk 等参数修改。
  3. Task 输出被清除:手动运行 clean、缓存目录被删除、CI 构建无本地缓存。
// 触发全量重新编译的典型配置变更
android {
    compileSdk 34       // compileSdk 变化 → 所有处理资源/代码的 Task 重新执行
    buildToolsVersion "35.0.0" // 仅影响部分打包 Task
    defaultConfig {
        minSdk 24       // 仅影响 manifest merger 及 multidex
    }
}
常见误解:修改 build.gradle 中 compileOptions 的 Java 版本,大部分 Android Task 不会增量,而是直接跳过或全量重跑—因为 Task 输入参数(Java 版本)属于 Task 输入的一部分,变更后缓存失效。

1.3 Task 缓存命中机制

AGP 基于 Gradle 的 Build Cache(构建缓存)实现 Task 复用。缓存的键由Task 输入属性的快照和Task 类的 hash共同决定。

缓存命中条件:当前 Task 的所有输入(源文件、注解处理器选项、编译参数等)的 hash 与缓存的 hash 完全一致,且 Task 实现类未升级。

以下场景会触发缓存失效:

  • 输入文件内容修改,但文件时间戳未变(跨机器构建常见)→ 依赖快照校验,使用 org.gradle.caching=true 可缓解。
  • Task 的 outputs.upToDateWhen 自定义规则返回 false。
  • 本地缓存目录被清除,远程缓存不可达。
// gradle.properties 中强制启用远程缓存
org.gradle.caching=true
org.gradle.caching.local.enabled=true
org.gradle.caching.http.url=https://cache.example.com:5000

1.4 调试构建阶段与缓存

使用 Gradle 自带的 --info 或 --debug 日志可观察每个 Task 是否 UP-TO-DATE、FROM-CACHE 或 重新执行。

./gradlew assembleDebug --info | grep "Task :" | head -20
# 输出示例:
# Task :app:preBuild UP-TO-DATE
# Task :app:mergeDebugResources FROM-CACHE
# Task :app:compileDebugKotlin EXECUTING
调试命令:使用 ./gradlew :app:tasks --group build 列出所有 Task 及其缓存属性;使用 --scan 生成构建扫描页面,直观查看阶段耗时。

1.5 性能与稳定性优化建议

  • 将 org.gradle.parallel=true 和 org.gradle.caching=true 加入 gradle.properties。
  • 避免在配置阶段执行 I/O 操作(如读取文件判断 SDK 版本),使用 afterEvaluate 或 task.doFirst 延迟执行。
  • 使用 AGP 的 android.enableR8.fullMode=true 减少混淆后的 Task 输入哈希波动。
  • 升级 Gradle 8.x + AGP 8.x,其中增量编译和缓存命中率显著提升(尤其是 Kotlin 编译)。
AGP 构建阶段与增量编译流程 1. 初始化 解析 settings.gradle 2. 配置 执行 build.gradle,生成 DAG 3. 执行 按 DAG 调度 Task 增量编译检查 文件内容 / 配置 / 时间戳 Task 缓存命中 输入快照 & Task 类 hash UP-TO-DATE / FROM-CACHE 重新执行 (EXECUTING) 提示:增量编译依赖 Task 注解,缓存命中依赖输入快照一致性。 使用 --info 日志确认每个 Task 的状态,定位增量失败原因。

1.6 常见错误与应对

  • “Task :app:compileDebugKotlin” 持续全量编译:检查 build.gradle 中是否在非配置阶段调用了 File.exists() 或 new File() 构造路径,导致输入快照不稳定。
  • 远程缓存命中但下载失败:配置 org.gradle.caching.http.connectTimeout=5000 和 readTimeout=30000,并确保远程缓存服务器返回正确的 ETag。
  • 增量编译后产物签名不一致:禁用 android.injected.build.config.only,在 release 构建中使用 isDefault = true 的 signingConfig。