Flutter中flutter_blue_plus库蓝牙BLE设备读取、监听及写入验证问询
Flutter flutter_blue_plus BLE 通信实操指南
BLE 与普通蓝牙/USB串口的核心差异
BLE是低功耗蓝牙,采用服务-特征值的分层通信模型:所有数据交互必须绑定到特定的特征值(Characteristic),而每个特征值属于一个服务(Service);普通蓝牙(经典蓝牙)和USB串口是字节流通信,不需要关注服务/特征的结构,直接收发数据即可。这是BLE通信最关键的区别,也是很多开发者踩坑的点。
一、用 flutter_blue_plus 监听BLE设备
实现代码
// 监听蓝牙开关状态 FlutterBluePlus.instance.state.listen((state) { if (state == BluetoothState.on) { // 蓝牙开启后启动扫描 _startDeviceScan(); } else { print('蓝牙未开启,请先打开蓝牙'); } }); // 扫描BLE设备 void _startDeviceScan() async { // 开始扫描,持续4秒可按需调整 await FlutterBluePlus.instance.startScan(timeout: const Duration(seconds: 4)); // 监听扫描结果 FlutterBluePlus.instance.scanResults.listen((scanResults) { for (ScanResult result in scanResults) { final device = result.device; print('发现设备: ${device.name.isNotEmpty ? device.name : '匿名设备'} | MAC/UUID: ${device.id}'); // 这里可以根据设备名称或ID过滤目标设备,比如保存到列表供用户选择 } }); // 扫描结束后停止 await FlutterBluePlus.instance.stopScan(); }
关键说明
- 扫描到的
BluetoothDevice实例是后续连接、读写操作的核心载体; - 部分设备可能不广播名称,需要用
device.id(Android是MAC,iOS是UUID)识别。
二、用 flutter_blue_plus 读取特征值
读取必须先发现设备的服务和特征值,且只能读取支持read属性的特征值:
实现代码
Future<void> _readCharacteristic(BluetoothDevice device) async { try { // 发现设备所有服务 List<BluetoothService> services = await device.discoverServices(); // 示例:根据设备文档的UUID定位目标服务和特征值(必须替换成你的设备UUID) const targetServiceUuid = '0000ffe0-0000-1000-8000-00805f9b34fb'; const targetCharUuid = '0000ffe1-0000-1000-8000-00805f9b34fb'; // 找到目标服务 final targetService = services.firstWhere( (s) => s.uuid.toString().toLowerCase() == targetServiceUuid, ); // 找到目标特征值 final targetChar = targetService.characteristics.firstWhere( (c) => c.uuid.toString().toLowerCase() == targetCharUuid, ); // 检查是否支持读取 if (targetChar.properties.read) { Uint8List data = await targetChar.read(); print('读取到原始数据: $data'); // 转成字符串(根据设备协议调整编码) String text = String.fromCharCodes(data); print('转译后内容: $text'); } else { print('该特征值不支持读取'); } } catch (e) { print('读取失败: $e'); } }
核心提示
绝对不要随便用services.last或characteristics.last来定位服务/特征,不同设备的服务顺序可能不固定,必须通过设备官方提供的UUID精准匹配。
三、你的写入代码验证与优化
原代码分析
List<BluetoothService> services = await selecteddevice!.discoverServices(); BluetoothService lastservice = services.last; BluetoothCharacteristic lastCharacterist = lastservice.characteristics.last; lastCharacterist.write(Uint8List.fromList([0xFF,0x02,0x24,0x00]),withoutResponse: true);
- 语法正确性:代码本身符合flutter_blue_plus的API规范,调用
write方法的参数格式没问题; - 致命隐患:直接取最后一个服务和特征值完全不可靠,大概率会写入到错误的特征值,导致设备无响应;
- withoutResponse参数说明:设为
true表示“无响应写入”,设备收到数据后不会回复,适合快速批量发送;如果需要确保设备收到数据,应设为false,此时write会返回Future,可通过try-catch捕获写入结果。
优化后的写入代码
Future<void> _writeToDevice(BluetoothDevice device) async { try { const targetServiceUuid = '0000ffe0-0000-1000-8000-00805f9b34fb'; // 替换成你的设备服务UUID const targetCharUuid = '0000ffe1-0000-1000-8000-00805f9b34fb'; // 替换成你的设备特征UUID List<BluetoothService> services = await device.discoverServices(); // 精准定位目标服务 final targetService = services.firstWhere( (s) => s.uuid.toString().toLowerCase() == targetServiceUuid, orElse: () => throw Exception('未找到目标服务'), ); // 精准定位目标特征值 final targetChar = targetService.characteristics.firstWhere( (c) => c.uuid.toString().toLowerCase() == targetCharUuid, orElse: () => throw Exception('未找到目标特征值'), ); // 检查是否支持写入 if (!targetChar.properties.write && !targetChar.properties.writeWithoutResponse) { throw Exception('该特征值不支持写入操作'); } // 写入数据(根据需求设置withoutResponse) await targetChar.write(Uint8List.fromList([0xFF,0x02,0x24,0x00]), withoutResponse: false); print('数据写入成功'); } catch (e) { print('写入失败: $e'); } }
四、flutter_blue_plus 替代库推荐
- flutter_reactive_ble:社区活跃度高,API采用响应式设计,支持多设备并发连接,内置连接状态管理,处理重连、断开等异常场景更稳定,适合复杂BLE项目;
- bleak:轻量级BLE库,专注核心功能,体积小,API简洁,适合需求简单的小型项目;
- flutter_ble_lib:基于原生BLE框架封装,稳定性优异,支持iOS/Android的高级特性(如后台扫描、长连接维护),适合对稳定性要求极高的场景。
内容的提问来源于stack exchange,提问作者Kürşat Şayhan
相关产品推荐
相关产品推荐

