1. Android SDK版本管理基础
做 Android 回归测试,第一件事就是弄清楚版本号到底怎么玩的。你想想看,每年 Google 发一个新版本,从 Android 10 到 11 再到 12,名字换来换去,但咱们在 Gradle 里配的其实是 API 级别。
我个人习惯把版本号拆成两套系统:一套是面向用户的「甜点名」(现在改数字了),另一套是面向开发者的「API Level」。后者才是我们真正需要关心的。Android 12 对应 API 31,Android 13 对应 API 33,Android 14 对应 API 34…… 这张对应表你最好记在脑子里,或者贴在工位上。
| Android 版本 | API Level | 发布时间(大致) |
|---|---|---|
| Android 4.4 (KitKat) | 19 | 2013 |
| Android 5.0 (Lollipop) | 21 | 2014 |
| Android 6.0 (Marshmallow) | 23 | 2015 |
| Android 7.0 (Nougat) | 24 | 2016 |
| Android 8.0 (Oreo) | 26 | 2017 |
| Android 9.0 (Pie) | 28 | 2018 |
| Android 10 | 29 | 2019 |
| Android 11 | 30 | 2020 |
| Android 12 | 31 | 2021 |
| Android 13 | 33 | 2022 |
| Android 14 | 34 | 2023 |
| Android 15 | 35 | 2024 |
compileSdkVersion、minSdkVersion、targetSdkVersion 分别是什么?
每次新建项目或者修改 build.gradle 时,你都会看到这三个家伙。我刚入行时也搞混过,后来有一次踩坑才彻底明白。
- compileSdkVersion:说白了就是「你拿哪个版本的 API 来编译代码」。比如你配了 34,你就可以用 Android 14 里新增的那些 API。但要注意,这只是一个编译时的约束,它不会影响真机运行。
- minSdkVersion:你的 App 最低支持到哪个 API 版本。比如你设成 21,那就意味着 Android 5.0 以下的手机根本装不了你的 App。我记得之前有个项目要求兼容 Android 4.4,结果 minSdkVersion 设成 19 之后,一大堆新 API 用不了,只能靠 Support Library 兜底。
- targetSdkVersion:这个字段最阴险。它告诉系统:「我是在哪个 API 级别上做的测试,请按那个版本的行为逻辑来运行我。」举个例子,Android 6.0 开始引入了运行时权限,如果你的 targetSdkVersion 低于 23,系统就会默认帮你兼容旧行为——不给用户弹权限请求,直接通过。但这其实是个隐患。我曾遇到过一个 App,targetSdkVersion 一直停在 28,结果上 Android 12 后,因为没适配 SplashScreen API,每次启动界面都怪怪的。
一句话记忆:compileSdkVersion 是你能用什么新东西,minSdkVersion 是你放弃了多少老用户,targetSdkVersion 是你承诺系统按哪个版本的行为干活。
android {
compileSdkVersion 34
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
// ...
}
}
版本号背后的行为差异——为什么要回归测试?
你可能会想:改动 targetSdkVersion 有什么大不了的?不就是升级个数字吗?嗯,我以前也这么想,直到有一次我把一个老项目的 targetSdkVersion 从 28 升到 31,结果用户反馈说「用不了存储卡了」。查了半天,原来是 Android 11 开始强制推行分区存储(Scoped Storage),而我代码里还在用老路径读写文件。
这种「静默行为变化」才是回归测试最该盯住的。哪怕你的代码一行都没改,只要 targetSdkVersion 变了,系统就会启用新的限制或特性。比如:
- 前台服务类型声明(Android 13+)
- 通知权限必须动态申请(Android 13+)
- 后台位置访问大幅受限(Android 10+)
- WiFi 扫描受限于精确位置权限(Android 8+)
每一个版本升级,都相当于给你的 App 换了一个「运行环境」。不做回归测试,就像开着一辆没检查刹车的车下山。
我的习惯:每次打算提升 targetSdkVersion 时,我会先翻一下 Android 版本行为变更文档,把影响自己功能的那几条圈出来,写进测试用例。然后至少跑一遍全量 monkey 测试和核心流程手工测试。
编译版本 vs 目标版本——到底听谁的?
编译版本决定了「你能调用的 API 集合」。目标版本决定了「系统怎么对待你的 App」。这两个不一定非要同步。你完全可以用 compileSdkVersion 34 编译,但 targetSdkVersion 还是 30。这样做的好处是,你可以提前用新 API 写代码,但暂时不触发新版本的行为变更,留给自己更多适配时间。
但要注意,Google Play 对 targetSdkVersion 有硬性要求。我记得从 2022 年开始,新上架的应用必须至少 target 到 API 31。所以别拖太久。
我曾经踩过的一个坑:在开发过程中为了测试新特性,把 compileSdkVersion 升到 34,但忘记同步升 targetSdkVersion。结果用户手机上 behavior 没变,但编译时用了新 API,导致代码里有些 deprecated 的用法没报错。上线后才发现某些场景下行为不符合预期。后来我强制规定:每次升级 compileSdkVersion 时,必须同步 review 一遍 targetSdkVersion 是否也该升了,至少要把行为变更清单过一遍。
把关系理清楚——一张图就够了
下面这张图把三个核心版本号以及它们与设备、代码的关系画了出来。看懂了它,你在配置 build.gradle 时心里就有底了。
看这张图时,重点看箭头方向。其实设备上的真实 API 级别是硬件决定的,我们无法改变。我们能控制的只有这三个配置。它们加起来,决定了 App 能跑在哪些设备上、能用新 API 吗、运行时系统给不给开绿灯。
一个小工具:检查当前设备的 API Level
做回归测试时,你可能需要快速知道测试手机的 API Level。用 adb 就能搞定:
adb shell getprop ro.build.version.sdk
它返回一个整数,比如 34。配合 ro.build.version.release 还能看到 Android 版本号。我常在写自动化脚本时先获取这个值,然后动态决定跑哪些测试集。
嗯,SDK 版本管理其实就是这么回事。数字背后藏着行为变化,而行为变化就是测试人员的战场。搞定这三个配置,你就迈出了多版本回归测试的第一步。