Flutter BLE自定义特征与服务:ESP32通信实现求助
问题分析与解决方案
你当前代码的核心问题是:自己手动创建的GattService和GattCharacteristic只是本地空对象,并没有和已连接的ESP32设备建立关联。bluetooth_low_energy库的读写方法需要的是从BLE设备实际发现、获取到的特征实例,不是你凭空构造的对象。
正确实现步骤
1. 连接设备后预存目标服务与特征
在设备连接成功的回调或流程中,调用discoverServices获取设备的所有服务和特征,筛选出你ESP32上定义的目标服务、特征,把它们保存到全局变量或状态管理(比如ValueNotifier、Provider)中:
// 假设已连接设备,保存设备实例 Peripheral connectedPeripheral; // 预存目标特征 GattCharacteristic targetWriteChar; GattCharacteristic targetReadChar; // 设备连接成功后调用 void discoverAndSaveCharacteristics() async { if (connectedPeripheral == null) return; // 发现设备所有服务 List<GattService> services = await connectedPeripheral.discoverServices(); // 遍历找到目标服务(替换成你ESP32的服务UUID) GattService targetService = services.firstWhere( (service) => service.uuid.toString() == 'ffeeddcc-bbaa-9988-7766-554433221100', orElse: () => null, ); if (targetService != null) { // 找到写特征(控制GPIO) targetWriteChar = targetService.characteristics.firstWhere( (char) => char.uuid.toString() == '你的写特征UUID' && char.properties.contains(GattCharacteristicProperty.write), orElse: () => null, ); // 找到读特征(获取传感器数据) targetReadChar = targetService.characteristics.firstWhere( (char) => char.uuid.toString() == '你的读特征UUID' && char.properties.contains(GattCharacteristicProperty.read), orElse: () => null, ); } }
2. 按钮直接调用预存特征执行读写
按钮点击时,直接用预存的特征实例操作,无需重新创建:
// 控制GPIO置1的按钮 ElevatedButton( onPressed: () async { if (targetWriteChar == null) { // 提示未找到目标特征或未连接设备 print('未连接设备或未找到目标特征'); return; } // 发送指令"1"(转成Uint8List) Uint8List command = Uint8List.fromList(utf8.encode('1')); await CentralManager.instance.writeCharacteristic( targetWriteChar, command, writeType: GattCharacteristicWriteType.withResponse, // 根据ESP32配置选择 ); print('已发送GPIO置1指令'); }, child: const Text('GPIO置1'), ), // 获取传感器数据的按钮 ElevatedButton( onPressed: () async { if (targetReadChar == null) { print('未连接设备或未找到目标特征'); return; } Uint8List sensorData = await CentralManager.instance.readCharacteristic(targetReadChar); // 解析数据,比如转成字符串或数字 String dataStr = utf8.decode(sensorData); print('传感器数据:$dataStr'); // 更新UI显示数据 // logs.value = [...logs.value, Log(LogType.read, sensorData)]; }, child: const Text('获取传感器数据'), ),
额外注意事项
- 确保ESP32端定义的服务UUID、特征UUID和Flutter端完全一致,大小写也要匹配。
- 操作前检查设备是否处于已连接状态,避免空指针异常。
- 安卓端需要申请BLE相关权限(
BLUETOOTH、BLUETOOTH_ADMIN、ACCESS_FINE_LOCATION等,根据系统版本调整)。
内容的提问来源于stack exchange,提问作者Jorge Monzon
相关产品推荐
相关产品推荐

