引入
pubspec.yaml1
| flutter_reactive_ble: ^5.0.3
|
Android
需要将以下权限添加到 AndroidManifest.xml 文件中:
1 2 3 4 5
| <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.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30"/>
|
如果用于BLUETOOTH_SCAN确定位置,请修改 AndroidManfiest.xml 文件以包含以下条目:
1 2 3 4
| <uses-permission android:name="android.permission.BLUETOOTH_SCAN" tools:remove="android:usesPermissionFlags" tools:targetApi="s"/>
|
如果在应用程序中使用位置服务,请android:maxSdkVersion=”30”从位置权限标签中删除
使用
建议连接蓝牙之前先获取权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| StreamSubscription<DiscoveredDevice>? _streamSubscription; StreamSubscription<ConnectionStateUpdate>? _connectionStreamSubscription; List<DiscoveredDevice> deviceList = []; var flutterReactiveBle = FlutterReactiveBle(); QualifiedCharacteristic? BLCharacteristic; QualifiedCharacteristic? BLCharacteristic2;
barcode= 'Test';
connectBluetooth() async { _streamSubscription = flutterReactiveBle.scanForDevices( withServices: [], scanMode: ScanMode.lowLatency).listen((device) { deviceList.add(device); print(device);
if (device.name == barcode) { print('扫描到${barcode}'); _streamSubscription?.cancel(); _connectionStreamSubscription = flutterReactiveBle .connectToDevice( id: device.id, servicesWithCharacteristicsToDiscover: {}, connectionTimeout: const Duration(seconds: 3), ) .listen((connectionState) async { if (connectionState.connectionState == DeviceConnectionState.connected) { print(" connectionState=${connectionState.deviceId}");
List<DiscoveredService> services = await flutterReactiveBle.discoverServices(device.id); print('获取所有服务 $services'); services.forEach((service) async { var characteristics = service.characteristicIds; print(characteristics);
for (Uuid char in characteristics) { print('获取到的特征值$char'); if (char.toString().contains("0000fff1")) { print("找到我们特征值$char"); BLCharacteristic = QualifiedCharacteristic( characteristicId: char, serviceId: service.serviceId, deviceId: device.id, ); print(BLCharacteristic); await setNotifiys2(); } if (char.toString().contains("0000fff2")) { BLCharacteristic2 = QualifiedCharacteristic( characteristicId: char, serviceId: service.serviceId, deviceId: device.id, ); print('获取到可以发送数据的特征值:$BLCharacteristic'); final mtu = await flutterReactiveBle.requestMtu( deviceId: device.id, mtu: 500); print('修改mtu为${mtu}'); update(); }
} }); } }, onError: (Object error) { print("error1 =$error"); connectBluetooth(); }); } }, onError: (e) async { print("onError = $e"); showToast("权限错误"); getPermissions(); }); }
|
设置通知
用到上面定义的变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Future<void> setNotifiys2() async { await flutterReactiveBle .subscribeToCharacteristic(BLCharacteristic!) .listen((data) { String msg = gbk_bytes.decode(data); print(data); print(msg.toString()); }, onError: (dynamic error) { print(error); }); }
|
gbk编码和解码
1 2 3 4
| gbk_bytes.decode(data)
gbk_bytes.encode(data)
|
如果是十六进制,但是是以字符串的形式,例如
String hex = 'b2e2cad4';
则需要先转换为字节数组,再进行解码
1 2 3 4 5 6 7 8 9 10 11
| String hex = 'b2e2cad4'; hexStringToBytes(hex);
List<int> hexStringToBytes(String hex) { List<int> bytes = []; for (int i = 0; i < hex.length; i += 2) { String part = hex.substring(i, i + 2); bytes.add(int.parse(part, radix: 16)); } return bytes; }
|
发送一个测试的字符串
1 2
| await flutterReactiveBle.writeCharacteristicWithResponse(BLCharacteristic2!, value: [0xb2, 0xe2, 0xca, 0xd4]);
|
发送中文字符串
1 2 3
| await flutterReactiveBle .writeCharacteristicWithResponse(BLCharacteristic2!, value:gbk_bytes.encode('测试') )
|
分包发送数据
每次发送数据后 等待 2 秒钟,如果没有收到回复,就抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| Future<void> sendHexDataInPackets2( String hexData, QualifiedCharacteristic characteristic, int packetSize, int delayMs, int maxRetries) async { int numPackets = (hexData.length / (packetSize * 2)).ceil(); String start = ''; print(start); await flutterReactiveBle .writeCharacteristicWithResponse(BLCharacteristic2!, value:gbk.encode(start) ) .timeout(Duration(seconds: 5), onTimeout: () { throw TimeoutException("Packet write timed out"); }); final threshold2 = Duration(seconds: 2); final startTime2 = DateTime.now(); while (true) { if (state.listenForStatus == '回复的数据') { state.listenForStatus= ''; break; } final elapsed = DateTime.now().difference(startTime2); if (elapsed > threshold2) { showToast('发送失败'); throw TimeoutException('Wait for status timed out'); } await Future.delayed(Duration(milliseconds: 5)); } List<String> packets = []; for (int i = 0; i < numPackets; i++) { String segment = hexData.substring( i * packetSize * 2, min((i + 1) * packetSize * 2, hexData.length)); packets.add(segment); } print('分包${packets.length}'); showToast('分包个数${packets.length}'); for (int i = 0; i < maxRetries; i++) { for (int j = 0; j < packets.length; j++) { try { List<int> bytes = hexStringToUint8List(packets[j]); showToast('发送第${j}包');
await flutterReactiveBle .writeCharacteristicWithResponse(BLCharacteristic2!, value: bytes) .timeout(Duration(seconds: 5), onTimeout: () { throw TimeoutException("Packet write timed out"); }); } catch (e) { print("Error sending packet $j in attempt ${i + 1}: $e"); if (i == maxRetries - 1) { rethrow; } else { await Future.delayed(Duration(milliseconds: delayMs)); } } await Future.delayed(Duration(milliseconds: delayMs)); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| Uint8List hexStringToUint8List(String hexString) { List<String> hexList = hexString.split(""); List<String> byteStrings = []; for (int i = 0; i < hexList.length; i += 2) { byteStrings.add(hexList[i] + hexList[i + 1]); } List<int> byteValues = byteStrings .map((byteString) => int.parse(byteString, radix: 16)) .toList(); return Uint8List.fromList(byteValues); }
|