Commit 5f699b5a authored by 18600395998's avatar 18600395998

修改蓝牙读写功能

parent 16cc47d9
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:anchor_collect_flutter/utils/dialog_utils.dart'; import 'package:anchor_collect_flutter/utils/dialog_utils.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import '../models/cattle_resume_entity.dart'; import '../models/cattle_resume_entity.dart';
import '../models/dict_entity.dart'; import '../models/dict_entity.dart';
...@@ -21,34 +23,39 @@ class BleService extends GetxService { ...@@ -21,34 +23,39 @@ class BleService extends GetxService {
late DiscoveredCallback? discoveredCallback; late DiscoveredCallback? discoveredCallback;
late ConnectCallback? connectCallback; late ConnectCallback? connectCallback;
// 添加一个 StreamController late BluetoothService _service;
final _readController = StreamController<List<int>>(); late BluetoothCharacteristic _writeCharacteristic;
late BluetoothCharacteristic _notifyCharacteristic;
Stream<List<int>> get readStream => _readController.stream; late
late Uuid _serviceId; // 读取数据的 Stream
late Uuid _writeCharacteristicId; List<BluetoothDevice> _systemDevices = [];
late Uuid _notifiCharacteristicId;
// 添加一个标志,用于控制读取循环是否应该继续 //
bool _shouldContinueReading = false; List<ScanResult> _scanResults = [];
RxBool isScanning = false.obs;
var isScanning = false.obs; late StreamSubscription<List<ScanResult>> _scanResultsSubscription;
final ble = FlutterReactiveBle(); late StreamSubscription<bool> _isScanningSubscription;
//判断是否正在扫描
StreamSubscription<DiscoveredDevice>? scanSubscription;
//判断设备选中状态 late StreamSubscription<BluetoothConnectionState>
final selectedDevice = Rx<DiscoveredDevice?>(null); _connectionStateSubscription;
//判断设备连接状态 late StreamSubscription<List<int>> _lastValueSubscription;
String deviceStatus = ''; late StreamSubscription<List<int>> _valueReceivedSubscription;
// ignore: cancel_subscriptions late BluetoothDevice selectedDevice;
late StreamSubscription<ConnectionStateUpdate> streamSubscriptionConnection;
Future<BleService> init() async { Future<BleService> init() async {
_isScanningSubscription = FlutterBluePlus.isScanning.listen((state) {
isScanning.value = state;
});
_scanResultsSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults = results;
}, onError: (e) {
DialogUtils.showToast('扫描错误');
});
return this; return this;
} }
...@@ -56,7 +63,7 @@ class BleService extends GetxService { ...@@ -56,7 +63,7 @@ class BleService extends GetxService {
Future<void> toggleScan(DiscoveredCallback callback) async { Future<void> toggleScan(DiscoveredCallback callback) async {
discoveredCallback = callback; discoveredCallback = callback;
if (isScanning.value) { if (isScanning.value) {
await scanSubscription?.cancel(); FlutterBluePlus.stopScan();
isScanning.value = false; isScanning.value = false;
} else { } else {
await scanDevices(); await scanDevices();
...@@ -68,130 +75,93 @@ class BleService extends GetxService { ...@@ -68,130 +75,93 @@ class BleService extends GetxService {
// 检查权限 // 检查权限
bool permissionsGranted = await requestBlePermissions(); bool permissionsGranted = await requestBlePermissions();
if (!permissionsGranted) { if (!permissionsGranted) {
Get.snackbar('Permissions required', 'Please grant all necessary permissions'); DialogUtils.showToast('请授予所有必要的权限');
return; return;
} }
// 扫描开始时,设置 isScanning 为 true // 扫描开始时,设置 isScanning 为 true
isScanning.value = true; isScanning.value = true;
// 扫描设备 try {
final scanStream = ble.scanForDevices( // android is slow when asking for all advertisments,
withServices: [], // so instead we only ask for 1/8 of them
int divisor = Platform.isAndroid ? 8 : 1;
//scanMode: ScanMode.balanced, // 将 scanMode 设置为 balanced 功耗均衡,扫描慢 await FlutterBluePlus.startScan(
scanMode: ScanMode.lowLatency, // 将 scanMode 设置为 lowLatency 功耗大 扫描快 timeout: const Duration(seconds: 15),
); continuousUpdates: true,
continuousDivisor: divisor);
// 监听扫描结果 } catch (e) {
scanSubscription = scanStream.listen((device) { DialogUtils.showToast('扫描错误');
// 如果设备名称不为空,且列表中没有该设备,则添加到列表中
if (device.name != null && device.name!.isNotEmpty) {
if (discoveredCallback != null) {
discoveredCallback!(device);
} }
}
});
///扫描10秒 ///扫描10秒
Future.delayed(const Duration(seconds: 15), () async { // Future.delayed(const Duration(seconds: 15), () async {
await scanSubscription?.cancel(); // FlutterBluePlus.stopScan();
isScanning.value = false; // isScanning.value = false;
DialogUtils.showToast('自动停止扫描'); // DialogUtils.showToast('自动停止扫描');
}); // });
} }
// 连接设备 // 连接设备
Future<void> connectToDevice(DiscoveredDevice device, BuildContext context, ConnectCallback callback) async { Future<void> connectToDevice(BluetoothDevice device, BuildContext context, ConnectCallback callback) async {
connectCallback = callback; connectCallback = callback;
selectedDevice.value = device; // 设置当前选中的设备 selectedDevice = device; // 设置当前选中的设备
await scanSubscription?.cancel(); // 在连接设备之前,停止扫描 // 在连接设备之前,停止扫描
await FlutterBluePlus.stopScan();
isScanning.value = false; // 设置 isScanning 为 false isScanning.value = false; // 设置 isScanning 为 false
DialogUtils.showLoadingDialog('正在连接到 ${device.name}'); DialogUtils.showLoadingDialog('正在连接到 ${device.name}');
// 显示正在连接的对话框 // listen for disconnection
// showDialog( _connectionStateSubscription = device.connectionState.listen((BluetoothConnectionState state) async {
// context: context, if (state == BluetoothConnectionState.disconnected) {
// barrierDismissible: false, // 1. typically, start a periodic timer that tries to
// builder: (BuildContext context) { // reconnect, or just call connect() again right now
// return AlertDialog( // 2. you must always re-discover services after disconnection!
// title: Text('Connecting to ${device.name}'), DialogUtils.showToast('断开连接');
// content: CircularProgressIndicator(), print(
// ); "${device.disconnectReason!.code} ${device.disconnectReason!.description}");
// }, } else if (state == BluetoothConnectionState.connected) {
// ); // Note: You must call discoverServices after every re-connection!
List<BluetoothService> services = await device.discoverServices();
// 连接设备 services.forEach((service) {
var connection = ble.connectToDevice( //打印所有服务的 uuid
id: device.id, print('service uuid: ${service.uuid}');
connectionTimeout: const Duration(milliseconds: 10000), if (!service.serviceUuid.toString().contains('000180')) {
servicesWithCharacteristicsToDiscover: {}, _service = service;
); //打印 service uuid
print('service uuid: ${service.uuid}');
// 监听连接状态 var characteristics = service.characteristics;
streamSubscriptionConnection = connection.listen((update) async { for (BluetoothCharacteristic c in characteristics) {
// 如果连接状态为 connected,则显示连接成功的提示 if (c.properties.write) {
if (update.connectionState == DeviceConnectionState.connected) { //打印写的特征值 uuid
// 发现服务和特性 print('write characteristic uuid: ${c.uuid}');
final services = await ble.discoverServices(device.id); _writeCharacteristic = c;
for (final service in services) { }
if (service.serviceId.toString() == '000180') { if (c.properties.notify) {
_serviceId = service.serviceId; //打印通知的特征值 uuid
if (kDebugMode) { print('notify characteristic uuid: ${c.uuid}');
print('Discovered service ${service.serviceId}'); _notifyCharacteristic = c;
} c.setNotifyValue(true);
for (final characteristic in service.characteristics) {
if(characteristic.isWritableWithoutResponse) { // _lastValueSubscription = c.lastValueStream.listen((value) {
_writeCharacteristicId = characteristic.characteristicId; // print(value);
if (kDebugMode) { // });
print('WritableWithoutResponse characteristic ${characteristic.characteristicId} of service ${service.serviceId}'); _valueReceivedSubscription = c.onValueReceived.listen((value) {
} print(value);
} });
if(characteristic.isNotifiable) {
_notifiCharacteristicId = characteristic.characteristicId;
if (kDebugMode) {
print('Notifiable characteristic ${characteristic.characteristicId} of service ${service.serviceId}');
}
}
}
} }
} }
// 设置最大传输单元
await ble.requestMtu(deviceId: device.id, mtu: 512);
await Future.delayed(const Duration(seconds: 1)); // 添加延迟
deviceStatus = 'Connected'; // 更新设备的连接状态
// Get.snackbar('Connected', 'Connected to ${device.name}');
// Navigator.of(context).pop();
if (connectCallback != null) {
connectCallback!(device);
}
// 关闭对话框
DialogUtils.dismissDialog();
} else if (update.connectionState == DeviceConnectionState.connecting) {
DialogUtils.showToast('设备连接中');
} else {
DialogUtils.dismissDialog();
DialogUtils.showToast('连接设备失败');
deviceStatus = 'Disconnected'; // 更新设备的连接状态
} }
}); });
} else if (state == BluetoothConnectionState.connecting) {
DialogUtils.showToast('正在连接');
} }
});
// 读取数据 // 连接设备
Future<List<int>> readData() async { await device.connect().catchError((onError) {
if (selectedDevice.value == null) { DialogUtils.showToast('连接设备失败$onError');
throw Exception('No device connected'); });
}
final characteristic = QualifiedCharacteristic(
deviceId: selectedDevice.value!.id,
serviceId: _serviceId,
characteristicId: _writeCharacteristicId,
);
final result = await ble.readCharacteristic(characteristic);
return result;
} }
// 写入数据 // 写入数据
...@@ -209,31 +179,6 @@ class BleService extends GetxService { ...@@ -209,31 +179,6 @@ class BleService extends GetxService {
await ble.writeCharacteristicWithResponse(characteristic, value: data); await ble.writeCharacteristicWithResponse(characteristic, value: data);
} }
// 启动循环读取数据
Future<void> startReading() async {
_shouldContinueReading = true;
while (_shouldContinueReading) {
// 读取数据
final data = await readData();
// 将数据添加到 Stream 中
_readController.add(data);
// 等待一段时间,然后再次读取数据
await Future.delayed(const Duration(seconds: 1));
}
}
// 停止循环读取数据
void stopReading() {
_shouldContinueReading = false;
}
@override
void onClose() {
_readController.close();
super.onClose();
}
// 检查权限 // 检查权限
Future<bool> requestBlePermissions() async { Future<bool> requestBlePermissions() async {
var isLocationGranted = await Permission.locationWhenInUse.request(); var isLocationGranted = await Permission.locationWhenInUse.request();
...@@ -253,4 +198,9 @@ class BleService extends GetxService { ...@@ -253,4 +198,9 @@ class BleService extends GetxService {
isBleConnectGranted == PermissionStatus.granted && isBleConnectGranted == PermissionStatus.granted &&
isBleAdvertiseGranted == PermissionStatus.granted; isBleAdvertiseGranted == PermissionStatus.granted;
} }
dipose() {
_isScanningSubscription.cancel();
_scanResultsSubscription.cancel();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment