项目基线搭建:目标与最低 SDK 选择、build.gradle 配置、manifest 权限声明

章节目标

本项目基线的搭建是后续所有蓝牙 API 向后兼容实践的起点。本章将指导你确定最低支持 SDK 版本、合理设定 targetSdk 和 compileSdk,配置模块级 build.gradle 文件,并精确声明蓝牙相关权限(包括经典蓝牙、BLE 及 Android 10 / 12 / 13 引入的新权限模型)。完成本节后,你将得到一个可在 5 个 Android 版本以上稳定运行、权限声明无冗余无缺失的工程基线。

原理:为什么基线搭建决定向后兼容成败

Android 蓝牙 API 从 API 18(Android 4.3)开始提供 BLE 支持,但经典蓝牙的 BluetoothAdapter 自 API 5 就已经存在。然而权限模型在以下版本发生了断裂式变化:

  • Android 10 (API 29):广播扫描和位置权限绑定,ACCESS_FINE_LOCATION 变为扫描 BLE 的必要条件。
  • Android 12 (API 31):引入 BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE、BLUETOOTH_CONNECT 运行时权限,旧版 BLUETOOTH / BLUETOOTH_ADMIN 不再用于运行时检查。
  • Android 13 (API 33):进一步细化,后台扫描需 ACCESS_BACKGROUND_LOCATION + 运行时权限组合。

如果 minSdk 过低但 targetSdk 过高,应用会在低版本设备上请求不存在的权限;反之,若 minSdk 过高则丢失大量用户。基线搭建的核心是找到“向下兼容”与“向上适配”的平衡点。

实现流程(6 步)

  1. 确定最低 SDK:经典蓝牙 + BLE 支持建议设为 minSdk = 21(Android 5.0),既能覆盖 95% 以上活跃设备,又避免处理 API 18~20 的碎片化 BLE 适配。
  2. 选择编译 SDK:始终使用最新稳定版(如 compileSdk = 34),以获得最新 API 声明。
  3. 设定 targetSdk:指向当前最新版(34),通知系统应用已适配新权限行为。
  4. 配置 build.gradle:添加 androidx.core:core 依赖以使用 ActivityCompat 运行时权限请求。
  5. 声明 manifest 权限:按 maxSdkVersion 限制旧权限,使用 uses-permission-sdk-23 和 android:maxSdkVersion 控制权限注入范围。
  6. 声明 uses-feature:明确 BLE 或经典蓝牙硬件要求,防止 Google Play 过滤。

build.gradle 配置示例

模块级 build.gradle(仅展示关键部分)

android {
    compileSdk 34

    defaultConfig {
        applicationId "com.example.blebackcompat"
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName "1.0.0"
    }
}

dependencies {
    implementation 'androidx.core:core:1.12.0'
    // 如需使用 BluetoothLeScanner 的 API 32+ 新方法,建议同时添加:
    implementation 'androidx.activity:activity:1.8.0'  // 用于 registerForActivityResult
}

manifest 权限声明(向后兼容写法)

以下配置同时兼容 Android 9(API 28)至 Android 14(API 34)。注意使用 android:maxSdkVersion 和 uses-permission-sdk-23:

<!-- 经典蓝牙(所有版本都需要,但 API 31+ 不再用于运行时) -->
<uses-permission android:name="android.permission.BLUETOOTH"
    android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="32" />

<!-- Android 12+ 细粒度运行时权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

<!-- 位置权限(BLE 扫描需要,API 29+ 为运行时,且 API 31+ 可声明 neverForLocation 免除) -->
<!-- 如果应用不使用 BLE 扫描位置,请添加 neverForLocation 属性 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
    android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
    android:maxSdkVersion="30" />

<!-- 硬件特性声明:告诉 Google Play 应用需要 BLE 功能 -->
<uses-feature android:name="android.hardware.bluetooth_le"
    android:required="false" />
<uses-feature android:name="android.hardware.bluetooth"
    android:required="false" />

调试与验证

  • 终端检查 manifest 合并结果:
    ./gradlew processDebugManifest --stacktrace
    # 查看输出文件 app/build/intermediates/merged_manifests/debug/AndroidManifest.xml
  • 运行时权限检查:使用 adb shell dumpsys package com.example.blebackcompat 查看授予的权限列表。
  • 模拟低版本设备:在 API 28、29、30、31 模拟器上分别测试权限请求对话框是否正常弹出。

常见错误与修复

错误场景原因解决方案
编译时报错 BLUETOOTH_SCAN 未找到compileSdk < 31将 compileSdk 提升至 31+
Android 12 设备上 BLE 扫描无回调缺少 BLUETOOTH_SCAN 运行时权限在 onRequestPermissionsResult 中处理新权限
Google Play 拒绝上架ACCESS_FINE_LOCATION 未声明 maxSdkVersion添加 android:maxSdkVersion="30" 限制
低版本设备闪退:找不到 BluetoothLeScanner未做 API 级别检查运行时判断 Build.VERSION.SDK_INT >= 18

性能与稳定性优化

  • 权限请求精简:仅当实际需要时才请求位置权限。设置 neverForLocation 标志可让 Android 12+ 设备不弹出位置对话框。
  • uses-feature 非必须:将 bluetooth_le 和 bluetooth 的 required 设为 false,避免无硬件的设备无法安装。
  • manifest 合并工具:在依赖库中如果引入了冲突权限(例如某些广告 SDK 声明了 ACCESS_BACKGROUND_LOCATION),使用 tools:remove="android:name" 移除。
实践要点: 确保 minSdk 不低于 21,targetSdk 和 compileSdk 指向最新版。在 manifest 中使用 maxSdkVersion 将旧权限限制在 API 30 及以下,新权限仅用于 API 31+。这一基线能让你在后续章节的蓝牙扫描、连接、广播编码时,省去 80% 的版本判断逻辑。

项目基线搭建流程图

Android 蓝牙基线搭建决策树 minSdk = 21 compileSdk = 34 targetSdk = 34 build.gradle 配置 依赖 androidx.core AndroidManifest.xml 权限声明 经典蓝牙权限 BLUETOOTH + BLUETOOTH_ADMIN maxSdkVersion=32 BLE 运行时权限 BLUETOOTH_SCAN neverForLocation 位置权限 ACCESS_FINE_LOCATION maxSdkVersion=30
新手提示: 在 Android Studio 中创建新项目时,直接选择 “API 21: Android 5.0” 作为最低 SDK,并在创建后手动将 compileSdk 和 targetSdk 改为最新版。然后一次性复制上方 manifest 权限块到你的 AndroidManifest.xml 中,即可获得最干净的基线。