第二章 经典蓝牙与BLE蓝牙选型:协议栈对比、功耗场景、Android版本兼容性、API差异

在Android蓝牙开发中,首先需要明确选型:使用经典蓝牙(Classic Bluetooth / BR/EDR)还是低功耗蓝牙(BLE / Bluetooth Low Energy)。两者虽共享“蓝牙”名称,但其协议栈、功耗特征、适用场景及Android API均存在根本差异。本章将从协议栈分层出发,对比功耗特性,梳理Android版本兼容性,并给出API差异与选型建议。

2.1 协议栈分层对比

经典蓝牙遵循BR/EDR规范,BLE遵循LE规范。两者在L2CAP层开始分化,上层协议完全不同。

协议层经典蓝牙(BR/EDR)BLE
射频79个1MHz信道,跳频79个40个2MHz信道,跳频37个+3个广播信道
链路层Baseband + LMPLink Layer(状态机:待机、广播、扫描、发起、连接)
HCIHCI(Host Controller Interface)HCI(相同标准,但命令集不同)
L2CAPL2CAP(面向连接,支持重传)L2CAP(基于BLE固定信道,无重传)
核心上层协议SDP + RFCOMM(串口仿真)+ GAPATT + GATT + GAP + L2CAP(面向属性)
ProfileSPP、HSP、A2DP、AVRCP等HID-over-GATT、Blood Pressure、Heart Rate等
关键差异:经典蓝牙使用RFCOMM提供虚拟串口通道,适用于双向流式数据传输;BLE基于属性协议(ATT),采用客户端-服务器模型,数据以“服务+特征值”结构化,适合周期性小数据交换。

2.2 功耗场景与选型建议

功耗是选型的首要考虑因素。经典蓝牙设计用于持续稳定连接,例如音频流(A2DP)或文件传输(OPP),典型工作电流为数十mA。BLE则针对低占空比、低功耗设计,一次连接传输几个字节后即可断开,待机电流可低至μA级。

应用场景推荐方案典型电流数据量特点
无线耳机、音箱(实时音频)经典蓝牙(A2DP)20~50 mA持续流式数据
心率带、温度计(传感器)BLE1~15 mA(广播/连接)小数据包,低频次
文件传输(Android快传)经典蓝牙(OPP)20~40 mA大文件,传输时持续
室内定位信标(Beacon)BLE广播0.1~0.5 mA(广播)仅发送ID,不连接
蓝牙键盘/鼠标(HID)BLE(HID-over-GATT)1~5 mA交互式小数据
选型口诀:需要持续数据流 → 经典蓝牙;需低功耗、小数据、周期性 → BLE;低延迟、指令型 → BLE(GATT Write)。

2.3 Android版本兼容性

BLE从Android 4.3(API 18)开始提供官方支持;经典蓝牙自Android 1.0起就存在。但随着系统升级,权限与扫描方式变化较大,需特别注意。

Android版本API LevelBLE支持经典蓝牙变化
4.3 (Jelly Bean)18引入BluetoothGatt、BluetoothLeScanner无重大变化
6.0 (Marshmallow)23扫描需要ACCESS_FINE_LOCATION同上
10 (Q)29扫描需ACCESS_FINE_LOCATION + 动态权限新增广播接收器限制
12 (Snow Cone)31新增BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限(无需定位)需SCAN/CONNECT权限
13+33+细化运行时权限,兼容NEARBY_DEVICES与BLE权限统一
注意:Android 10及以上,经典蓝牙扫描(startDiscovery)同样需要ACCESS_FINE_LOCATION。Android 12后,使用BLE扫描可以单独请求BLUETOOTH_SCAN,不再强制定位权限,但经典蓝牙发现仍可能需要定位权限(因Wi-Fi/蓝牙联合扫描)。

2.4 API差异速查

经典蓝牙与BLE在核心API上差异显著,开发时必须区分使用。

操作经典蓝牙(BR/EDR)BLE
获取适配器BluetoothAdapter.getDefaultAdapter()相同
扫描设备startDiscovery()/cancelDiscovery()BluetoothLeScanner.startScan()
发现结果回调BroadcastReceiver 监听 ACTION_FOUNDScanCallback 接口
发起连接BluetoothDevice.createRfcommSocketToServiceRecord()device.connectGatt()
数据收发InputStream/OutputStream (基于RFCOMM)BluetoothGatt.read/writeCharacteristic() + 回调
服务发现BluetoothDevice.fetchUuidsWithSdp() 或手动SDP查询BluetoothGatt.discoverServices()
广播(Beacon)不支持主动广播BluetoothLeAdvertiser.startAdvertising() (Android 5.0+)
// 经典蓝牙 —— 通过RFCOMM收发数据
BluetoothDevice device = adapter.getRemoteDevice(address);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(MY_UUID);
socket.connect();
OutputStream os = socket.getOutputStream();
os.write(data);
InputStream is = socket.getInputStream();
int bytes = is.read(buffer);

// BLE —— 通过GATT读写特征值
BluetoothGatt gatt = device.connectGatt(context, false, gattCallback);
gatt.discoverServices();
// 在onServicesDiscovered回调中操作
BluetoothGattService service = gatt.getService(SERVICE_UUID);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHAR_UUID);
gatt.readCharacteristic(characteristic);
// 或 gatt.writeCharacteristic(characteristic);

2.5 常见错误与调试建议

  • 经典蓝牙连接超时:确保配对已完成,UUID匹配,且在异步线程中调用connect()。
  • BLE扫描不到设备:检查权限(Android 12+需BLUETOOTH_SCAN),确认设备在广播;部分设备需要先启动扫描过滤。
  • GATT错误133:通常为连接参数协商失败,尝试设置连接间隔为30ms~50ms(Peripheral端需支持)。
  • 经典蓝牙与BLE干扰:两者共用同一射频,同时启用可能降低性能;建议场景分离。
调试技巧:使用Android Studio的“Bluetooth HCI snoop log”工具(开发者选项 → 启用蓝牙HCI信息收集日志),抓取hci_log,配合Wireshark分析协议层问题。

2.6 协议栈选型结构图

下图展示经典蓝牙(左侧)与BLE(右侧)的协议栈层次对比,并标注关键分界点。

经典蓝牙与BLE协议栈对比 经典蓝牙(BR/EDR) Profile(A2DP, SPP, HFP…) RFCOMM / SDP L2CAP(面向连接) HCI Baseband + LMP BR/EDR Radio BLE Profile(HOGP, BLP, HRS…) GATT / ATT L2CAP(固定信道) HCI Link Layer LE Radio L2CAP分水岭 经典蓝牙用于流式/大数据传输;BLE用于低功耗、小数据、广播场景 选型需考虑功耗、数据量、Android版本权限约束

2.7 性能与稳定性优化要点

  • 经典蓝牙:避免在主线程进行RFCOMM连接,使用AsyncTask或线程池;合理设置SO_TIMEOUT防止死等。
  • BLE:控制连接间隔(Connection Interval)在30~50ms以平衡功耗与响应;批量读写时使用Reliable Write或Queued Write。
  • 共存场景:避免同时大量经典蓝牙和BLE扫描,可先暂停经典发现再启动BLE扫描。
  • 内存管理:及时释放BluetoothSocket和BluetoothGatt对象,防止泄漏。
总结:经典蓝牙与BLE并非替代关系,而是互补。优先根据通信场景选型:
• 音频、文件传输 → 经典蓝牙
• 传感器、信标、遥控 → BLE
• 若需要两者共存(如同时接听蓝牙耳机和接收心率数据),则需分开管理连接与扫描周期,避免射频冲突。