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 决定用什么工具打包。版本要匹配,要么不写。别让构建工具版本拖垮你。