Gradle 9.7.0 将提速 Android 构建,Sync 提升接近一倍

Android 最近和 Gradle 官方合作,在 9.7.0 版本推出了全新的 Gradle Isolated Projects ,简单来说就是 Gradle 现在开始把大型多模块工程的「配置阶段」改成能安全并行运行,同时未来还能按模块增量缓存的架构

现在对 Android 开发来说,appfeature-homecore-networkcore-ui 这些 Gradle Project,以前虽然看起来都是独立 module,但配置阶段其实可以互相读写状态,所以 Gradle 很难安全地同步配置它们,然后现在 Isolated Projects 给这些 Project 之间加了一道强约束边界,然后就可以并行配制了,在 Gradle 9.7 开始,这个支持从 experimental 提升到了 incubating,未来还会变成为默认模式。

以后 Gradle 一次构建大体是:

arduino 复制代码
Initialization
    ↓
Configuration
    ↓
Execution
​
读 settings        执行每个 module 的 build.gradle       javac/kotlinc/package...
                   创建 Task
                   配置 Plugin
                   解析各种 Project 状态

也就是大家平时说的 Android Studio Sync Project with Gradle Files 很大一部分时间都花在 Configuration 上,比如一个 500 个 module 的大型项目,过去逻辑上接近:

ruby 复制代码
:app
 │
 ├─ configure
 ↓
:core
 │
 ├─ configure
 ↓
:network
 │
 ├─ configure
 ↓
:feature-home
 │
 ├─ configure
 ↓
...

但是在过去这个配置行为不能简单地丢进线程池,因为 Gradle 历史上的 Build DSL 存在这种玩法:

javascript 复制代码
// :app/build.gradle.kts
​
​
val version = rootProject.version
​
​
project(":network").tasks.named("xxx") {
    ...
}
​
​
rootProject.subprojects {
    // 修改其他 project
}

也就是说 A 配置到一半可以摸 B,B 又可能摸 C :

arduino 复制代码
Project A configuration
        │
        ├──────────► Project B mutable state
        │
        └──────────► Root Project mutable state

如果把他们放到多线程里同步支持,但是出现这种情况的话:

css 复制代码
Thread 1 → configure A
Thread 2 → configure B
Thread 3 → configure C

搜一 Gradle 保证不了执行顺序和状态一致性,callback 顺序和插件行为也会混乱,task 的注册也可能出现问题,所以 Gradle 多模块工程长期存在一个很严重的「配置阶段共享可变状态」问题 ,而 Isolated Projects 做的核心事情实际上也很简单,它主要规定了:

arduino 复制代码
        :app
     ┌─────────┐
     │ mutable │
     │ state   │
     └─────────┘
          X
          │ 禁止直接碰
          X
     ┌─────────┐
     │ mutable │
     │ state   │
     └─────────┘
     :network

每个 Project 的配置逻辑只能安全操作自己的 mutable state,例如:

java 复制代码
rootProject.version
project(":foo").tasks
project(":foo").dependencies
project(":foo").configurations
project(":foo").extensions

这类跨 Project 「读取/修改可变状态」会被 Gradle 判成 Isolated Projects violation,官方甚至建议可以简单理解成:

除少数 immutable getter 外,基本别去调用另一个 Project 的东西。

而诸如另一个 Project 的 namepathprojectDir buildFile 这种在配置开始前已经确定的 immutable 信息还是可以读取,所以实际上这是在 Gradle DSL 上建立一个新的 concurrency contract,有了这个 contract 就可以:

css 复制代码
以前
​
​
Project A ──► B
    │        ▲
    ▼        │
Project C ◄──┘
​
​
不知道谁依赖谁的状态
→ 不敢并行
​
​
​
​
Isolated Projects
​
​
┌ A ┐   ┌ B ┐   ┌ C ┐   ┌ D ┐
└───┘   └───┘   └───┘   └───┘
  │       │       │       │
 CPU1    CPU2    CPU3    CPU4
​
​
→ 可以安全并行配置

所以 Gradle 9.7 大的实际收益就是 Parallel Project Configuration。

而在 Android Studio Sync 的时候,Studio 会让 Gradle 构建大量 Tooling Model,例如:

ruby 复制代码
Gradle
​
​
:app
 ├─ Android model
 ├─ dependency model
 ├─ source sets
 └─ variants
​
​
:featureA
 ├─ Android model
 ├─ dependency model
 └─ variants
​
​
:featureB
 ...
        │
        ▼
Android Studio

以前 Project configuration 本身存在共享状态,IDE 获取这些 model 的并行度一直受到限制,但是现在 Isolated Projects 开启以后:

ruby 复制代码
CPU 1 → configure :app       → model
CPU 2 → configure :featureA  → model
CPU 3 → configure :featureB  → model
CPU 4 → configure :core      → model
CPU 5 → configure :network   → model

Gradle 官方自己的测试工程效果就很显著:

如果是 5000+ Project Android monorepo ,甚至可以做到 5m09s -> 2m44s 这种优化,所以这东西对十几个 module 的普通 App 感知可能一般,但是对几百到几千 module 的 Android monorep 影响还是挺大的。

而且它和 Configuration Cache 其实是一条路线,可以粗略理解成:

复制代码
Configuration Cache
       │
       │ 解决:
       ▼
上次配置没变?
→ 那这次整个 Configuration 都别跑了
​
​
​
​
Isolated Projects
       │
       │ 解决:
       ▼
配置必须重新跑?
→ 那各个 Project 并行跑

所以整体架构情况大概类似:

css 复制代码
              Configuration Cache
                       │
              ┌────────┴────────┐
              │                 │
          Cache Hit          Cache Miss
              │                 │
       Configuration          Isolated
          全跳过              Projects
                                │
                     Project A ─┬─ Project B
                               ├─ Project C
                               └─ Project D
                             并行配置

也就是 Isolated Projects 其实是直接建立在 Configuration Cache 基础设施之上 ,所以开启 org.gradle.isolated-projects=true ,Gradle 就会自动启用 Configuration Cache,显式关掉 Configuration Cache 甚至会报错。

不过它和 org.gradle.parallel=true 完全不是一回事,parallel 主要解决的是:

ruby 复制代码
Execution Phase
​
​
:app:compile
:libA:compile
:libB:compile
      ↓
任务并行

而 Isolated Projects 解决的是:

ruby 复制代码
Configuration Phase
​
​
configure :app
configure :libA
configure :libB
      ↓
Project 配置并行

这两者还不太一样,不过 Gradle 官方也说了,这是他们和 Google、JetBrains 合作一起实现的支持,也就是从项目到 IDE 到参与了这次优化。

但是老项目可能会有一些风险,比如自定义 Gradle 脚本或者第三方 plugin 如果存在 cross-project access , 打开 Gradle Isolated 可能就直接配置失败了。

不过说真的,对于国区来说,Sync 最大耗时根本不在这里,实际上这个优化大部分时候聊胜于无,而且升级 Gradle 9.7.0,还是很需要勇气的。

相关推荐
时代分流37 分钟前
云手机推荐2026:安卓全能、批量挂机、原生iOS全覆盖
android·ios·智能手机
lilian23339 分钟前
Harmony os 技术实战|拼豆制图48:把个人页字符串路由改成可穷尽的类型协议
前端·华为·harmonyos
咏方舟【长江支流】1 小时前
【前端2】单据编辑 -订单单据主子表,万能模板行,自定义添加行
前端·前端框架·状态模式·咏方舟-长江支流
qq_452396231 小时前
第六篇:《CI/CD 流水线:从前端构建到自动化部署》
前端·ci/cd·自动化
咏方舟【长江支流】1 小时前
【前端1】单据编辑 -EasyUI/Vue/React/Bootstrap 主流框架实现订单单据主子表显示和编辑比较,哪个你最易入门?
前端·vue.js·easyui·咏方舟-长江支流·userbaodatagrid
m0_579146651 小时前
Element UI 表格合并单元格完全指南:从原理到实战
前端·vue.js·elementui
Dovis(誓平步青云)1 小时前
心情日记的安全编辑流程:输入校验、删除确认与状态回收
android·运维·服务器·开发语言·windows·安全
sibylyue1 小时前
# Web端流媒体JS播放器开源库
前端·javascript·开源
iFlyCai1 小时前
Flutter三棵树核心详解之Widget树完全解析(二)
flutter·statelesswidget