第2章:Android SDK开发环境搭建与版本管理(Java/Kotlin、Gradle、MinSDK等)

这一章,我们聊聊环境搭建和版本管理。说实话,这步看着基础,但SDK兼容性测试的根基就在这里。我见过太多人因为Android SDK版本没配好,最后测试环境跟生产环境不一致,白白浪费了宝贵的测试时间。

你想想看,一个数据分类SDK要跑在成千上万的设备上。如果开发环境都不稳,那后面所有测试都像是在沙子上盖房子。

核心目标: 构建一个可重复、高可信的开发环境,确保SDK在编译期、运行期都能准确反映其真实行为和兼容性边界。

2.1 开发环境链路概览

我先把整条环境链路理一遍。一条干净的工具链,能帮你省下70%的排查时间。

Android SDK 开发环境与版本管理核心流程 开发环境链路 JDK 17 Gradle 8.x Android SDK 34 compileSdk minSdk targetSdk 构建变体(Debug / Release) 混淆 / 资源缩减 构建输出:AAB / APK 兼容性检查点: API可用性 → 行为变更 → 动态特性分包

2.2 JDK与Gradle版本管理

JDK版本,我建议统一用JDK 17。 为什么?因为从Android Gradle Plugin 8.x开始,官方正式要求JDK 17支持。我之前项目里,就因为JDK版本不同导致JNI库加载失败,排查了整整一个下午。

我的习惯: 在项目根目录新建一个 .java-version 文件(用 jEnv 工具),确保团队所有成员本地JDK一致。这种小事,往往是最容易出问题的。

Gradle版本,尽量保持跟AGP(Android Gradle Plugin)大版本匹配。

AGP 版本 最低 Gradle 版本 我建议的 Gradle 版本 备注
7.x 7.5 7.6.x 旧项目过渡用
8.0 - 8.1 8.0 8.2 稳定版本
8.2+ 8.2 8.4 或 8.5 推荐新项目使用

有次我接手一个数据采集SDK项目,里面还在用AGP 4.2和Gradle 6.7。编译一次要5分钟,而且各种警告。升级到AGP 8.x后,编译时间缩短到1分钟以内,而且很多废弃API的检查自动生效。

2.3 Kotlin / Java 语言版本配置

对于SDK开发,我倾向于用Kotlin + Java 11的混合模式。数据分类SDK里,核心逻辑用Kotlin协程处理,底层IO操作有时还是Java更稳。

注意 compileOptions 里的 sourceCompatibility 和 targetCompatibility。


android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    kotlinOptions {
        jvmTarget = "11"
    }
}
避坑指南: 我曾经在升级AGP后忘了更新 kotlinOptions.jvmTarget,结果编译出来的字节码版本不匹配,在Android 12设备上运行时抛出 UnsupportedOperationException。这个问题非常隐蔽,因为编译不会报错,只有运行到特定API才会暴露。

2.4 MinSdk / TargetSdk / CompileSdk 三件套

这三者的关系,说白了就是“你用什么编译”、“你最低支持到哪”、“你适配的目标版本是什么”。

  • compileSdk: 用最新的(比如34)。让你能调用的API最多,编译检查也最严。
  • minSdk: 根据你的SDK用户群体定。数据分类SDK如果面向大型App,通常minSdk=21(Android 5.0)或更高。我个人习惯定在24左右。
  • targetSdk: 这个必须小心。它决定了系统会对你施加哪些行为变更(Behavior Changes)。你测试时必须用targetSdk对应的设备版本来验证。

android {
    compileSdk = 34

    defaultConfig {
        minSdk = 24
        targetSdk = 33   // 建议保守一点,让系统行为变更可控
    }
}

我曾经遇到过:targetSdk设为34后,Android 14的“非线性通知”机制导致我们的数据分类服务被系统频繁切断。幸好我们在兼容性测试中提前发现了。

2.5 版本号与依赖管理

版本号管理看似简单,但坑很多。数据分类SDK的版本号通常由 versionCode(数字,严格递增)和 versionName(字符串,语义化)组成。

字段 用途 建议 我在项目中遇到过的坑
versionCode 内部递增,用于市场判断 用时间戳或构建流水线ID 手动设置 -> 漏跟版本 -> 上线被回滚
versionName 对外展示 Semantic Versioning (major.minor.patch) 建议同步到Git Tag

另外,依赖版本的锁定也很关键。Gradle的 constraints 和 platform 可以帮助你统一依赖版本,避免依赖地狱。


dependencies {
    constraints {
        implementation("com.google.code.gson:gson:2.10.1") {
            because("要求2.10.1版本以修复CVE-2022-xxxxx")
        }
    }
}

2.6 构建变体(Build Variants)与测试

对于SDK兼容测试,我至少要配置两个变体:debug 和 release。

为什么?因为release版本会经过混淆(R8/ProGuard)和资源缩减。

一个惨痛教训: 我曾经只测试了debug变体就直接发布SDK,结果release包在运行时一直报ClassNotFoundException。原因:混淆规则没配全,某个数据分类的model类被R8优化掉了。

建议在 build.gradle.kts 里设置如下规则:


android {
    buildTypes {
        debug {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

2.7 工程化与版本锁定

我建议所有项目成员都使用 gradle-wrapper.properties 和 gradle/libs.versions.toml(Gradle版本目录)来统一版本。

举个例子,你的 gradle/libs.versions.toml 文件可以这样写:


[versions]
agp = "8.2.0"
kotlin = "1.9.22"
gson = "2.10.1"

[libraries]
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }

然后在构建脚本里引用:


plugins {
    id("com.android.library") version "8.2.0" apply false
}

这样做的最大好处: 版本变更只需要改一个文件,CI/CD流水线也能自动获取最新版本。降低人为错误。

我的习惯: 每次升级 compileSdk 或 targetSdk 后,都会用 adb shell dumpsys package 检查一下当前设备的运行时权限和后台限制是否被触发。这个步骤能帮你发现一些很难复现的兼容性问题。

2.8 小结

环境搭建和版本管理,是整个SDK兼容性测试的“地基”。地基稳了,后面所有测试才有意义。我觉得你这会儿可以先去检查一下自己项目的 build.gradle.kts,看看 minSdk 和 targetSdk 是否都在预期范围内。