移动端开发进阶之蓝牙通讯(四)
在移动端开发实践中,可能会要求在不同的设备之间切换,从而提升用户体验;
或者为了提升设备的利用率,实现设备之间的连接和协同工作;
不得不通过多端连接,将多个设备连接在一起,实现设备之间的数据共享、远程控制等功能,根据具体的应用场景和需求采用蓝牙的多端连接进行实现。
一、选择合适的第三方库
要实现多设备蓝牙连接需要选择使用flutter_reactive_ble或flutter_ble_lib,下面用flutter_reactive_ble作为示例。
dependencies:flutter:sdk: flutterflutter_reactive_ble: ^5.2.0
二、连接设备
- 扫描设备
final FlutterReactiveBle reactiveBle = FlutterReactiveBle();final List<DiscoveredDevice> devices = [];StreamSubscription<DiscoveredDevice>? scanStream;StreamSubscription<ConnectionStateUpdate>? connectStream;// 开始扫描Future<void> scanDevices() async {List<Uuid> services = [];/*** 过滤条件,不过滤就传空数组* services.add(Uuid.parse("0000fff0-0000-1000-XXXX-XXXXXXXXXXX"));* */scanStream = reactiveBle.scanForDevices(withServices: services, scanMode: ScanMode.lowLatency).listen((device) {// 验证重复性、验证合法性才能添加进devicesdevices.add(device);}, onError: (e) {debugPrint("onError = $e");});}// 停止扫描Future<void> stopScan() async {scanStream?.cancel();}
- 连接设备
// 连接设备Future<void> connectDevices({id}) async {if (id == null) {for (var device in devices) {connectDevices(id: device.id);}return;}/*** connectStream* 这里可以根据实际情况使用不同的容器存储* 如果是多端连接就需要使用HashMap去存储* */connectStream = reactiveBle.connectToDevice(id: id,servicesWithCharacteristicsToDiscover: {},connectionTimeout: const Duration(seconds: 3)).listen((state) {switch (state) {case DeviceConnectionState.connected:break;case DeviceConnectionState.connecting:break;case DeviceConnectionState.disconnected:break;case DeviceConnectionState.disconnecting:break;}}, onError: (e) {debugPrint("onError = $e");});}// 断开连接Future<void> disconnectDevice() async {connectStream?.cancel();}
- 识别服务
// 过滤和识别对应的服务Future<void> discoverServices(String id) async {reactiveBle.getDiscoveredServices(id).then((services) {for (var service in services) {if (service.characteristics.length < 4) {/*** service.deviceId* 过滤和保存服务、特征* service.id* service.characteristics* */}}});}
三、数据收发
- 订阅特征
// 订阅特征Future<void> listenCharacteristic(id) async {final characteristic = QualifiedCharacteristic(characteristicId: Uuid.parse("xxxx"),serviceId: Uuid.parse("xxxx"),deviceId: id);reactiveBle.subscribeToCharacteristic(characteristic).listen((data) {// 周期性地读取特征,可以在值发生变化时监听通知}, onError: (e) {debugPrint("onError = $e");});}
- 发送数据
// 发送数据Future<void> sendCharacteristic(id) async {final characteristic = QualifiedCharacteristic(characteristicId: Uuid.parse("xxxx"),serviceId: Uuid.parse("xxxx"),deviceId: id);reactiveBle.writeCharacteristicWithoutResponse(characteristic, value: [0x00]);}
- 读取数据
// 读取数据Future<void> readCharacteristic(id) async {final characteristic = QualifiedCharacteristic(characteristicId: Uuid.parse("xxxx"),serviceId: Uuid.parse("xxxx"),deviceId: id);final respone = await reactiveBle.readCharacteristic(characteristic);debugPrint("respone = $respone");}
有时后为了节约电量或性能需要在设备长时间未操作时自动断开连接,这时候如果需要保持持久连接就需要像TCP类似的使用心跳包。
四、MTU调整
MTU的调整需要硬件的配合。
final mtu = await reactiveBle.requestMtu(deviceId: id, mtu: 250);
五、设置连接优先级
针对Android设备,可以设置连接优先级,但是当前是多端连接所以要特别谨慎。
await reactiveBle.requestConnectionPriority(deviceId: id, priority: ConnectionPriority.highPerformance);
六、GATT缓存清理
await reactiveBle.clearGattCache(id);