1. Android蓝牙开发环境搭建
本章聚焦 Android 蓝牙开发的初始步骤:正确配置 SDK 版本、理解模拟器与真机的行为差异、获取 BluetoothAdapter 对象,并避开最常见的开发陷阱。所有后续蓝牙通信与本地存储的章节都依赖于本章搭建的基础环境。
1.1 SDK 版本配置要点
Android 蓝牙 API 在 API 级别 18(Android 4.3)进行了重大重写。目前主流的开发目标应至少覆盖 API 21(Android 5.0)以上,但要注意最低版本对经典蓝牙和低功耗蓝牙(BLE)的支持差异。
| 蓝牙类型 | 最低 API Level | 建议 targetSdkVersion | 核心类 |
|---|---|---|---|
| 经典蓝牙 (RFCOMM) | API 5 (Android 2.0) | ≥ 29 (Android 10) | BluetoothDevice, BluetoothSocket |
| 低功耗蓝牙 (BLE) | API 18 (Android 4.3) | ≥ 31 (Android 12) | BluetoothLeScanner, BluetoothGatt |
| 蓝牙 LE Audio (新) | API 33 (Android 13) | ≥ 34 (Android 14) | BluetoothLeAudio |
编译配置注意点: 如果项目使用
compileSdkVersion 34 但 minSdkVersion 21,仍然可以使用蓝牙 RFCOMM 和 BLE,但需要运行时检查 Android 版本,避免调用仅在 API 33+ 上可用的方法。
build.gradle (Module: app) 典型配置
android {
compileSdk 34
defaultConfig {
applicationId "com.example.ble_storage_demo"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
}
...
}
dependencies {
// 蓝牙 BLE 扫描(可选)
implementation "androidx.activity:activity:1.9.1"
}
1.2 模拟器 vs 真机 —— 关键差异
绝大多数 Android 模拟器(包括 Android Studio 自带模拟器和 Genymotion)不支持蓝牙硬件模拟。即使使用“扩展控制”中的“蓝牙”设置,也只是虚拟界面,无法真实打开或关闭射频。
| 对比维度 | 模拟器 | 真机 |
|---|---|---|
| BluetoothAdapter 是否可用 | 返回 null(多数情况) | 返回有效实例 |
| 蓝牙开关控制 | 不可调用 enable()/disable()(会抛异常或静默失败) | 正常控制并弹出系统对话框 |
| 设备发现 / 扫描 | 无真实扫描结果;模拟器会返回空列表或固定测试数据 | 返回周围真实设备 |
| 建立连接 (RFCOMM/GATT) | 无法建立物理连接;连接回调会超时报错 | 正常建立 |
| 位置权限要求 (BLE) | 仍然需要 ACCESS_FINE_LOCATION 声明,但不会触发实时位置请求(Android 12+ 已改) | 必须动态请求位置权限,否则 BLE 扫描无结果 |
| 开发调试建议 | 仅用于 UI 测试、权限弹窗逻辑验证 | 蓝牙功能测试唯一有效环境 |
开发建议: 使用真机 + USB 调试或 Wi‑Fi ADB 作为主要调试手段。如果必须使用模拟器,可考虑安装第三方蓝牙虚拟驱动(如 Bluetooth LE Simulator),但仅适用于 BLE 通信的 UI 逻辑验证,不适用于物理连接测试。
1.3 获取 BluetoothAdapter 的标准方式
BluetoothAdapter 代表本地蓝牙设备。获取实例必须通过系统服务 BluetoothManager,从 Android 4.3 开始推荐这种做法,可以保证在高版本系统上的兼容性。
推荐实现流程
- 在 AndroidManifest.xml 中声明必要权限(见下文)。
- 调用
Context.getSystemService(Context.BLUETOOTH_SERVICE)获取 BluetoothManager。 - 通过
bluetoothManager.getAdapter()获取 BluetoothAdapter 实例。 - 检查返回是否为 null —— 如果为 null 则表示设备不支持蓝牙(或者模拟器无蓝牙驱动)。
完整代码片段
private BluetoothAdapter getBluetoothAdapter(Context context) {
BluetoothManager manager = (BluetoothManager) context
.getSystemService(Context.BLUETOOTH_SERVICE);
if (manager == null) {
return null; // 系统服务不可用(极少情况)
}
return manager.getAdapter();
}
// 使用示例
BluetoothAdapter adapter = getBluetoothAdapter(context);
if (adapter == null) {
// 设备不支持蓝牙(或模拟器)
Toast.makeText(context, "此设备不支持蓝牙", Toast.LENGTH_LONG).show();
return;
}
if (!adapter.isEnabled()) {
// 启动蓝牙(通常需要用户确认)
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
AndroidManifest.xml 权限声明
<!-- 经典蓝牙 (API 5+) -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- BLE (API 18+) -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 定位(用于 BLE 扫描,Android 12+ 已弱化,但低版本仍需) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
<!-- 如果 app 也需要网络/蓝牙进行位置推测,可以声明粗略位置 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
android:maxSdkVersion="30" />
<!-- 硬件特性声明(可选,用于阻止不支持蓝牙的设备安装) -->
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
1.4 常见坑点与调试方法
- 模拟器 getAdapter() 返回 null
这是新手最容易遇见的“死结”。请务必在真机上测试蓝牙功能。如果必须用模拟器,可加入条件判断代码使 App 降级运行(不崩溃)。 - Android 12+ (API 31) 权限拆分
从 Android 12 开始,蓝牙扫描权限需要动态请求BLUETOOTH_SCAN和BLUETOOTH_CONNECT,而不再是依赖位置权限。如果在 targetSdk >= 31 的 app 中只请求位置权限,扫描将无结果。 - 未打开蓝牙时调用 startDiscovery() 导致 IllegalStateException
必须先检查adapter.isEnabled(),如果未启用,通过ACTION_REQUEST_ENABLE引导用户打开。 - Android 10 限制非系统应用扫描
从 Android 10 开始,普通应用无法扫描到类型为“不可发现”的经典蓝牙设备,BLE 扫描也受后台扫描限制。需要申请ACCESS_BACKGROUND_LOCATION(Android 10-11)或使用前台服务。 - 重复获取 BluetoothAdapter 导致内存泄漏
BluetoothAdapter 是单例,每次调用BluetoothAdapter.getDefaultAdapter()或manager.getAdapter()返回的都是同一个对象,无需缓存。但若在 Activity 或 Fragment 中频繁调用系统服务,注意不要在非 UI 线程长期持有 Context 引用。
调试日志查看技巧: 蓝牙相关的日志 Tag 通常为
BluetoothAdapter、BluetoothManager、BluetoothDevice、BluetoothGatt。使用命令 adb logcat -s BluetoothAdapter:V BluetoothManager:V BluetoothGatt:V 查看详细状态。
1.5 环境搭建流程图
下面的 SVG 流程图展示了从配置 SDK 到成功获取 BluetoothAdapter 并开始使用的整体步骤:
1.6 小结
通过本章的学习,你已经掌握了蓝牙开发的基本环境配置步骤:
- 正确设置
compileSdk与minSdk,并加入必要的蓝牙权限声明。 - 认清模拟器无法模拟蓝牙硬件的限制,坚持使用真机测试。
- 使用
BluetoothManager.getAdapter()获取 BluetoothAdapter 实例,并进行 null 检查与开关状态处理。 - 避开常见的权限、版本兼容和错误处理陷阱。