2. 版本号机制

版本号这东西,表面上看就是几个数字加小数点。但真到项目里,你遇到的不匹配崩盘、打包失败,十有八九都是版本号体系没搞明白。我见过太多团队因为升级了一个小版本号,结果炸了构建整整一天。

说白了,Android 构建体系依赖三套版本号:语义化版本(SemVer)、AGP 版本号、Gradle 版本号。它们必须像齿轮一样咬合,错一个齿,整个链条就转不动。

1. 语义化版本(SemVer)—— 一切规则的原点

语义化版本的定义很简单:Major.Minor.Patch,比如 3.2.1。

  • Major(主版本号):不兼容的 API 修改。我升级一次就是伤筋动骨,建议立项初期就锁定。
  • Minor(次版本号):向下兼容的功能新增。比如 AGP 从 7.4 升到 8.0,很多旧写法就要停用。
  • Patch(修订号):向下兼容的问题修正。这个最安全,但也不。

你以为这就完了?还有预发布标识,比如 7.4.0-alpha04、8.0.0-rc01。我记得有一次,团队把一个 RC 版本当正式版引用,结果 Gradle 缓存解析出了歧义,构建直接报了令人费解的版本冲突。

我的经验:正式项目永远不要用 -alpha、-beta、-rc 后缀的版本。除非你明确在测试新功能,否则就是引雷。

2. AGP 版本号规则 —— 它不是纯粹的 SemVer

Android Gradle Plugin 号称遵守语义化版本,但实际有自己的一套“潜规则”。比如 AGP 7.4.0 和 7.4.1 看起来只是 Patch 差异,但如果你用的 Gradle 版本不一样,可能 7.4.1 甚至启动不了。

我习惯把 AGP 版本号理解为三部分:

主版本号.次版本号.补丁版本号[-后缀]

举个例子:8.2.0-alpha07。这里后缀表示预发布阶段。正式版本没有后缀,比如 8.2.0。

但你得注意,AGP 有一个坑:同一个主版本号里,补丁版本和 Gradle 的最低要求也在变。比如 AGP 7.0 要求 Gradle 7.0+,但 AGP 7.3 却要求 Gradle 7.4+。你表面上升了一个小补丁,实际上底层 Gradle 依赖已经变了。

我曾经踩过的坑:在 CI 上用了 AGP 7.3.1,结果本地构建正常,CI 却报 Minimum supported Gradle version is 7.4。最后发现 AGP 7.3.1 的兼容矩阵里写的是 Gradle 7.4+,而 CI 的 Gradle 版本还是 7.3。

3. Gradle 版本号规则 —— 和 AGP 的“婚姻关系”

Gradle 本身也遵循 SemVer。比如 Gradle 8.0、8.1、8.2。它和 AGP 有一个官方定义的兼容矩阵,类似下面这样(部分数据,实际以官方最新发布为准):

AGP 版本 最低 Gradle 版本 建议 Gradle 版本 备注
7.0.x 7.0 7.0 – 7.3 支持 Java 11
7.4.x 7.4 7.4 – 7.6 注意 AGP 7.4.1 需要 Gradle 7.5+
8.0.x 8.0 8.0 – 8.2 AGP 8.0 开始强制 Java 17
8.1.x 8.1 8.1 – 8.4 推荐 Gradle 8.2

这张表看起来很简单,但实际使用中经常出现“半兼容”状态。比如 AGP 8.1 在 Gradle 8.3 上也能跑,但某些内部 API 已经被标记为废弃,未来版本会直接报错。

关键指标:每次升级 AGP 之前,先查官方兼容矩阵。不要只看 AGP 文档里写的最低版本,还要看建议版本和已知问题列表。

4. 不匹配时的典型错误 —— 你八成见过

当 AGP 和 Gradle 版本不匹配时,构建失败的错误信息往往藏得很深。我整理了几个典型场景:

  1. Gradle 版本过低:
Minimum supported Gradle version is 7.4.
Current version is 7.3.

这个错误最直白,直接告诉你缺版本。

  1. AGP 与 Kotlin 插件版本冲突:
Error: Unable to find method 'org.gradle.api.file.DirectoryProperty.getAsFile()'
Cause: class 'org.gradle.api.file.DirectoryProperty' was compiled with an incompatible version of Gradle.

这种错误往往让人摸不着头脑。我遇到过,查了一天发现是 AGP 8.0 用到了 Gradle 8.0 才有的 API,但项目实际用的是 Gradle 7.6。

  1. 子模块间 AGP 版本不一致:
Plugin [id: 'com.android.application'] was requested but not found.
This is often caused by having multiple versions of the Android Gradle plugin in the same project.

如果你在根项目里声明了 AGP 8.1,某个子模块又单独声明了 AGP 7.4,就会触发这个错误。解决办法是统一版本号管理。

5. 版本匹配决策流程

下面这张图展示了我个人处理版本号匹配时的决策逻辑。每次升级前我都会过一遍这个流程,能避免 90% 的构建崩盘:

AGP 与 Gradle 版本匹配决策流程 SemVer 语义版本 AGP 版本(如 8.1.2) 查询兼容 矩阵表 匹配 Gradle 版本确认 ✅ 构建成功 不匹配 调整 AGP 或 Gradle 重新选择版本 💡 避坑指南 • 升级 AGP 前先查官方兼容矩阵(含最低与建议 Gradle 版本) • 不同子模块的 AGP 版本必须统一,否则触发“Plugin not found”错误 • 记得用 Gradle Wrapper 锁定版本,避免 CI 与本地版本不一致

6. 个人习惯:如何避免版本号引起的崩溃

我在团队里定了三条铁律:

  1. 用 Gradle Wrapper 锁定 Gradle 版本。不要靠本地系统变量,那个坑过我好几次。
  2. 版本号统一写在根项目的 build.gradle 的 ext 块里。子模块全部引用,防止不同模块撞版本。
  3. 升级前先看 Release Notes。很多 Minor 版本看似向下兼容,实则废弃 API 会在 Patch 版本里突然不可用。

我之前接手一个项目,AGP 7.2.0 和 Gradle 7.2 组合在 CI 上跑了一年都没事。某天升级了 AGP 到 7.2.1 后,构建突然报错,原因是 7.2.1 内部依赖了一个仅在 Gradle 7.3 中存在的 API。从那以后,我每次升级 Patch 版本至少会看下兼容矩阵的变更日志。

版本号不匹配导致的崩溃往往不是由 AGP 直接抛出的,而是藏在 Gradle 的配置阶段报错里。你看到 Could not resolve plugin 或者 Task requires property 这类奇怪错误时,第一反应就应该是检查 AGP 和 Gradle 的版本关系。

好了,版本号机制就聊到这儿。理解了这个基础,之后讲具体冲突场景时你就能秒懂底层原因。