2. 常用Gradle配置项

做 Android 开发这么久,我见过太多因为这几个配置写错而导致的崩溃了。说实话,大多数人只会无脑复制粘贴,一遇到编译问题就蒙圈。今天咱们就把这几个配置项彻底整明白。

2.1 这四个配置是干什么的?

先看一个典型的 build.gradle(Module 级别)长啥样:

android {
    compileSdk 34
    buildToolsVersion "34.0.0"

    defaultConfig {
        applicationId "com.example.myapp"
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName "1.0"
    }
}

嗯,这里要注意:compileSdk 和 buildToolsVersion 是写在 android 块里的,而 minSdk 和 targetSdk 是放在 defaultConfig 里的。位置不同,含义也完全不同。我刚开始学的时候经常搞混,编译报错了才去翻文档。

一句话总结:
compileSdk 决定你能用哪些新 API;minSdk 决定你的应用最低支持哪款手机;targetSdk 告诉系统你做过针对该版本的适配测试;buildToolsVersion 是编译用的工具链版本。

2.2 compileSdk —— 你能用到的最新武器

compileSdk 说白了,就是告诉 Gradle:“我编译的时候,可以用到哪个 API 级别的库?” 你设为 34,那就能用 Android 14 提供的新接口,比如 Android 13 引入的 NotificationManager.areNotificationsEnabled()。如果你设为 33,那这些新 API 就报红。

常见误区:有人把 compileSdk 和 targetSdk 写成一样的,就觉得万事大吉。其实不对。compileSdk 只管编译时能不能调用,而 targetSdk 管的是运行时行为。

我曾经踩过的坑: 某次我把 compileSdk 直接从 30 跳到 33,结果 MediaStore 新增的分区存储限制直接在旧手机上跑崩了。因为 compileSdk 高不等于 targetSdk 高,我只是能用新 API,但运行时行为还得看 targetSdk。后来我学乖了——升级 compileSdk 后一定要手动检查所有用了新 API 的地方。

2.3 minSdk —— 你的应用能活多久

这个值决定了你的 App 最低支持到哪个 Android 版本。比如 minSdk 21,那 Android 5.0 以下的手机就直接装不了。为什么要设这个?因为低版本系统缺乏很多现代 API,你要处理大量兼容代码。

行业惯例:

minSdk 值 覆盖设备比例(2024年数据) 典型场景
21 (Lollipop) 95%+ 大多数商业 App
26 (Oreo) 85%+ 追求现代 API 的新应用
31 (Android 12) 60%+ 只适配旗舰机的游戏

我个人习惯把 minSdk 设到 21,除非产品明确说不要老机型。因为 21 以下很多 AppCompat 和 Jetpack 库都不维护了,你想想看,你要自己手写 ActivityCompat 兼容代码,多痛苦。

警告:minSdk 不能高于 compileSdk,否则 Gradle 会直接报错。另外,minSdk 也不能大于 targetSdk,虽然不报错,但逻辑上不合理——你编译时用高版本 API,却告诉系统你只适配低版本,运行时很容易出问题。

2.4 targetSdk —— 系统的“信任票”

这个是最容易被忽略的配置。很多初学者觉得 targetSdk 随便写个 30 就完了。但你知道吗?Google Play 从 2023 年开始强制要求新应用 targetSdk 至少 31,更新应用也要逐步升级。

targetSdk 的核心作用是:告诉系统,你的 App 已经测试过在这个版本上的行为表现,系统可以开启该版本的新特性约束。比如 Android 10(API 29)引入了后台定位权限变化,如果你的 targetSdk 低于 29,系统就会用旧的行为兼容你的 App,不限制后台定位。但一旦你升到 29 或更高,就必须处理运行时权限。

我举个例子:

  • targetSdk = 28(Android 9):在 Android 10 手机上运行,系统不启用 BACKGROUND_LOCATION 限制,你的定位代码老样子。
  • targetSdk = 29(Android 10):系统会强制你使用 ACCESS_BACKGROUND_LOCATION 权限,如果没声明,定位服务就会静默失败。

为什么会这样?因为 Google 希望开发者主动适配新系统。你想想,如果所有 App 都写 targetSdk 18,那新系统岂不是永远用不上新特性?

我的建议: targetSdk 始终跟随 compileSdk,或者比 compileSdk 低一个版本(比如 compileSdk 34,targetSdk 33)。这样你既能用到最新的编译 API,又有时间在新特性强制生效前做适配测试。我一般会在发布前的一个季度把 targetSdk 升到最新,留出三个月消化兼容性问题。

2.5 buildToolsVersion —— 被遗忘的工具链

这个是 Android SDK Build-Tools 的版本号,用来编译、打包 APK。从 AGP 3.0 开始,大部分情况下 buildToolsVersion 可以被省略,Gradle 会自动匹配一个合适的版本。但我还是要讲一下,因为不小心写错了会翻车。

buildToolsVersion 的版本号格式是 major.minor.patch,比如 34.0.0。需要注意:

  • 它必须与 compileSdk 匹配:比如 compileSdk 34,最好用 buildToolsVersion 34.x.x,否则可能出现 aapt2 错误。
  • 它不能低于 AGP 的最低要求:比如 AGP 8.x 要求 buildToolsVersion >= 30.0.3。
  • 如果省略,AGP 会自动选用已安装的最高版本——但可能不是最稳定的。

我个人习惯明确写上,因为我曾遇到过:某同事电脑上装了 33.0.1 和 34.0.0 两个版本,自动选了 34.0.0,结果编译出来的 APK 在 Android 12 上解析失败。查了俩小时,发现 34.0.0 的 aapt2 对旧资源格式有兼容问题。最后升到 34.0.1 解决。

避坑指南: 团队统一在 build.gradle 里写上 buildToolsVersion,不要依赖自动选择。另外注意,Android Studio 的 SDK Manager 里有时会同时存在多个 build-tools 版本,最好删掉旧的,只保留 2~3 个最新版本。

2.6 它们之间的关系图

下面这张图能帮你快速理清这四个配置项在编译和运行时的作用位置:

Gradle 常用配置项关系图 编译时阶段 compileSdk buildToolsVersion 决定能调用的 API 版本 决定编译工具链版本 运行时阶段 minSdk targetSdk 最低支持的 Android 版本 声明已适配的系统版本 影响运行时行为 常见异常对应关系 • compileSdk 太低 → 无法调用新 API,编译报错 • minSdk 太低 → 兼容代码膨胀,lint 警告 • targetSdk 太低 → 系统不启用新特性限制,但可能被 Play 商店拒绝 • buildToolsVersion 不匹配 → aapt2 报错或 APK 解析失败 建议:compileSdk ≥ targetSdk ≥ minSdk,buildToolsVersion 显式指定

2.7 其他相关配置(简单提一句)

applicationId 是 App 的唯一标识,和包名可能不同——但大部分项目都设成一样。versionCode 是整型,给商店判断版本升级用;versionName 是展示给用户的版本号,可以写 "2.1.0" 这种格式。这两个虽然不属于 Sdk 配置,但也是 defaultConfig 里的常客,我一般会写个 versionCode = 100 * major + 10 * minor + patch 的规则方便管理。

2.8 实战检查清单

最后分享一个我每次新建项目都会做的检查清单:

  1. 确认 compileSdk = 最新稳定版(目前是 34)
  2. minSdk 根据产品需求定,不要贪高也别太低
  3. targetSdk 跟上最新的,但保留一个版本的安全窗口
  4. buildToolsVersion 显式指定,并确保 SDK Manager 里已安装
  5. 全部设好后跑一次 ./gradlew assembleDebug 检查无警告

嗯,以上就是这几个配置项的核心内容。你想想看,其实它们都围绕一个核心:编译时用尽量新的 API,运行时给系统一个明确的适配声明,同时守住最低兼容底线。弄懂它们,你就能避免很多莫名其妙的编译崩溃了。