2. compileSdkVersion 与 buildToolsVersion 配置错误

说实话,AGP 配置里最常见的坑,就是这两个版本号。一个是 compileSdkVersion,一个是 buildToolsVersion。很多人觉得它们差不多,混着用,结果构建一跑就崩。

我自己刚开始带项目的时候,也理不清这俩的区别。直到有一次,同事改了 compileSdkVersion 没改 buildToolsVersion,编译过了,运行时 crash 了。嗯,那次加班到半夜…今天我们就把它彻底掰扯清楚。

核心概念:compileSdkVersion 告诉编译器“你可以调用哪些 API”;buildToolsVersion 告诉构建工具“你用哪一套工具链来打包”。前者是 API 的权限,后者是打包的手艺。

2.1 配置错误长什么样

我给你看一个典型错误。有人在 build.gradle 里这么写:

android {
    compileSdkVersion 34
    buildToolsVersion "34.0.0"  // 这里写错了
    defaultConfig {
        applicationId "com.example.demo"
        minSdkVersion 21
        targetSdkVersion 34
    }
}

构建日志里报了一个错:

ERROR: The specified build tools version (34.0.0) is incorrect.
Please install the requested version.

为什么会这样?很简单。你没有安装 34.0.0 这个版本的构建工具,或者它根本不存在。你想想看,SDK Manager 里可能只装了 34.0.0-rc1 或者 33.0.2,你却指名要 34.0.0,那不就报错了吗?

2.2 compileSdkVersion 低版本引用高版本 API

这是一个更隐蔽的错误。我记得有一次,项目里用了一个第三方库,它依赖的是 API 33 才有的方法。但我的 compileSdkVersion 写的是 31。结果编译直接报:

error: cannot find symbol class NotificationChannel

这是因为 NotificationChannel 是 API 26 才引入的。如果你的 compileSdkVersion 低于 26,编译器根本不知道有这么个类,自然就找不到了。

所以原则很简单:保持 compileSdkVersion 不低于你依赖的所有库的最低要求。我一般会把它设成当前最新的稳定版本(比如现在的 34),这样就能调最新的 API,也不会因为用了旧 API 被抱怨。

场景 错误的配置 正确的配置
引用高版本 API compileSdkVersion 31,但用了 API 33 的类 compileSdkVersion 33 或更高
buildToolsVersion 不存在 buildToolsVersion "34.0.0" buildToolsVersion "34.0.0" 或使用 AGP 自动选择
安装不匹配 buildToolsVersion "33.0.0" 但本地没装 先安装对应版本,或用 AGP 自动检测

2.3 AGP 3.0.0 之后的版本变化

这里有个重要的转折点。AGP 从 3.0.0 开始,不再强制要求你配置 buildToolsVersion。如果你不写,它会自动使用最低兼容版本。我推荐的做法是干脆不写,让 AGP 自己决定。

但如果你非要写,就必须保证该版本已安装。我见过很多新人,从老项目的 build.gradle 里复制了 buildToolsVersion "25.0.3",但电脑上只装了 34.0.0 的版本,结果编译失败。嗯,这种问题最不值得。

我的建议:在 AGP 3.0.0+ 的项目中,干脆移除 buildToolsVersion 这一行。既少了一个出错点,又减少了配置冗余。维护成本最低的方式就是让框架帮你做决定。

2.4 版本组合的陷阱

还有更微妙的陷阱:compileSdkVersion 和 buildToolsVersion 要相互协调。compileSdkVersion 越高,需要的 buildToolsVersion 也越高。比如你用 compileSdkVersion 34,但 buildToolsVersion 只写 30.0.3,这个组合在 AGP 4.x 里可能没问题,但到 AGP 7.x 就会报版本不兼容。

我曾经踩过一个坑:我用 compileSdkVersion 31 搭配 buildToolsVersion 32.0.0,结果 AGP 7.2 直接报错,说 build-tools 版本必须 >= compileSdkVersion。后来查文档才发现,这是 AGP 7.x 的新限制。所以版本组合一定要与 AGP 版本对齐。

2.5 版本对应关系一览

为了方便你自查,我整理了一张版本对应表。注意,这只是常见的推荐值,不是的。

AGP 版本 推荐 compileSdkVersion 推荐 buildToolsVersion
3.0.x - 3.6.x 28 - 30 28.0.3 - 30.0.3
4.0.x - 4.2.x 30 - 32 30.0.3 - 32.0.0
7.0.x - 7.4.x 31 - 34 31.0.0 - 34.0.0
8.0.x - 8.3.x 33 - 35 33.0.0 - 35.0.0

你可能会问,如果我不写 buildToolsVersion,它怎么知道用哪个?AGP 会从本地安装的版本里挑一个最低的、但与 compileSdkVersion 兼容的。所以,只要你本地安装了对应的大版本就行。

注意:buildToolsVersion 不是越小越安全,也不是越大越好。太小可能不支持新的 API,太大可能引入不必要的兼容问题。如果你实在不知道配多少,就别配了——交给 AGP 自动选择。

2.6 案例:从构建失败到修复

最后给你一个真实案例。我做的一个项目,compileSdkVersion 是 33,但 buildToolsVersion 配的是 32.0.0。构建的时候报了一个警告:

WARNING: The specified build tools version (32.0.0) is less than the
minimum version required by AGP 7.0.0. The build may fail.

我没在意,继续跑。后来报了一个找不到 R class 的错误,整整卡了半天。最后排查出来,就是因为 build-tools 版本太低,导致 aapt2 无法正常处理资源。我改成了 buildToolsVersion "33.0.0",问题立刻消失。

我后来复盘:如果当初直接不写 buildToolsVersion,根本不会出这个事。所以,我现在的习惯是:在 AGP 3.0.0+ 项目中,直接删掉 buildToolsVersion 配置。少一个变量,多一分稳定。

课后一句话:compileSdkVersion 决定你能调什么 API,buildToolsVersion 决定用什么工具打包。版本要匹配,要么不写。别让构建工具版本拖垮你。

compileSdkVersion 与 buildToolsVersion 配置关系与错误流程 compileSdkVersion 与 buildToolsVersion 配置关系图 compileSdkVersion buildToolsVersion AGP 版本 决定 API 级别 决定工具链版本 compileSdkVersion 过低 引用高版本 API 失败 buildToolsVersion 不存在 或版本过低/过高 版本组合不兼容 AGP 7.x 限制 构建失败 / 运行时崩溃 编译错误、找不到类、资源异常 解决方案 保持版本一致,推荐删除 buildToolsVersion 配置