You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.4 KiB
281 lines
7.4 KiB
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart' as fbp;
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'package:app_settings/app_settings.dart';
|
|
|
|
class BleController extends GetxController {
|
|
// 扫描状态
|
|
final RxBool isScanning = false.obs;
|
|
final RxBool isBluetoothOn = false.obs;
|
|
final RxBool hasPermissions = false.obs;
|
|
|
|
// 发现的设备列表
|
|
final RxList<fbp.ScanResult> scanResults = <fbp.ScanResult>[].obs;
|
|
|
|
// 连接的设备
|
|
final Rx<fbp.BluetoothDevice?> connectedDevice =
|
|
Rx<fbp.BluetoothDevice?>(null);
|
|
|
|
// 错误信息
|
|
final RxString errorMessage = ''.obs;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initBluetooth();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
stopScan();
|
|
super.onClose();
|
|
}
|
|
|
|
// 初始化蓝牙
|
|
Future<void> _initBluetooth() async {
|
|
try {
|
|
// 先检查权限
|
|
await _checkPermissions();
|
|
|
|
// 检查蓝牙适配器状态
|
|
fbp.FlutterBluePlus.adapterState.listen((state) {
|
|
isBluetoothOn.value = state == fbp.BluetoothAdapterState.on;
|
|
if (state == fbp.BluetoothAdapterState.on) {
|
|
errorMessage.value = '';
|
|
} else {
|
|
errorMessage.value = 'pleaseEnableBluetooth'.tr;
|
|
stopScan();
|
|
}
|
|
});
|
|
|
|
// 监听扫描结果
|
|
fbp.FlutterBluePlus.scanResults.listen((results) {
|
|
scanResults.value = results;
|
|
});
|
|
|
|
// 监听扫描状态
|
|
fbp.FlutterBluePlus.isScanning.listen((scanning) {
|
|
isScanning.value = scanning;
|
|
});
|
|
} catch (e) {
|
|
errorMessage.value = 'bleInitFailedWithError'.trParams({'error': e.toString()});
|
|
}
|
|
}
|
|
|
|
// 检查权限(不请求)
|
|
Future<void> _checkPermissions() async {
|
|
try {
|
|
Map<Permission, PermissionStatus> statuses = await [
|
|
Permission.bluetoothScan,
|
|
Permission.bluetoothConnect,
|
|
Permission.location,
|
|
].request();
|
|
|
|
hasPermissions.value =
|
|
statuses.values.every((status) => status == PermissionStatus.granted);
|
|
|
|
if (!hasPermissions.value) {
|
|
errorMessage.value = 'needBluetoothAndLocationPermission'.tr;
|
|
}
|
|
} catch (e) {
|
|
print('检查权限失败: $e');
|
|
hasPermissions.value = false;
|
|
}
|
|
}
|
|
|
|
// 请求权限
|
|
Future<bool> _requestPermissions() async {
|
|
try {
|
|
Map<Permission, PermissionStatus> statuses = await [
|
|
Permission.bluetoothScan,
|
|
Permission.bluetoothConnect,
|
|
Permission.location,
|
|
].request();
|
|
|
|
bool allGranted =
|
|
statuses.values.every((status) => status == PermissionStatus.granted);
|
|
hasPermissions.value = allGranted;
|
|
|
|
if (!allGranted) {
|
|
// 检查是否有权限被永久拒绝
|
|
bool hasPermanentlyDenied = statuses.values
|
|
.any((status) => status == PermissionStatus.permanentlyDenied);
|
|
|
|
if (hasPermanentlyDenied) {
|
|
_showPermissionDialog();
|
|
} else {
|
|
errorMessage.value = 'needBluetoothAndLocationPermission'.tr;
|
|
}
|
|
}
|
|
|
|
return allGranted;
|
|
} catch (e) {
|
|
print('请求权限失败: $e');
|
|
errorMessage.value = 'permissionRequestFailedWithError'.trParams({'error': e.toString()});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 显示权限对话框
|
|
void _showPermissionDialog() {
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text('needPermission'.tr),
|
|
content: Text('blePermissionDialogContent'.tr),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text('cancel'.tr),
|
|
),
|
|
TextButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
AppSettings.openAppSettings();
|
|
},
|
|
child: Text('goToSettings'.tr),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 显示蓝牙开启对话框
|
|
void _showBluetoothDialog() {
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text('needEnableBluetooth'.tr),
|
|
content: Text('enableBluetoothDialogContent'.tr),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text('cancel'.tr),
|
|
),
|
|
TextButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
// 尝试开启蓝牙
|
|
fbp.FlutterBluePlus.turnOn();
|
|
},
|
|
child: Text('enableBluetooth'.tr),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 开始扫描
|
|
Future<void> startScan() async {
|
|
try {
|
|
errorMessage.value = '';
|
|
|
|
// 检查权限
|
|
if (!hasPermissions.value) {
|
|
if (!await _requestPermissions()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 检查蓝牙状态
|
|
if (!isBluetoothOn.value) {
|
|
_showBluetoothDialog();
|
|
return;
|
|
}
|
|
|
|
// 清空之前的结果
|
|
scanResults.clear();
|
|
|
|
// 开始扫描
|
|
await fbp.FlutterBluePlus.startScan(
|
|
timeout: const Duration(seconds: 30),
|
|
androidUsesFineLocation: true,
|
|
);
|
|
} catch (e) {
|
|
errorMessage.value = 'bleScanFailedWithError'.trParams({'error': e.toString()});
|
|
}
|
|
}
|
|
|
|
// 停止扫描
|
|
Future<void> stopScan() async {
|
|
try {
|
|
await fbp.FlutterBluePlus.stopScan();
|
|
} catch (e) {
|
|
print('停止扫描失败: $e');
|
|
}
|
|
}
|
|
|
|
// 连接设备
|
|
Future<void> connectToDevice(fbp.BluetoothDevice device) async {
|
|
try {
|
|
errorMessage.value = '';
|
|
|
|
// 停止扫描
|
|
await stopScan();
|
|
|
|
// 连接设备
|
|
await device.connect(timeout: const Duration(seconds: 15));
|
|
connectedDevice.value = device;
|
|
|
|
Get.snackbar(
|
|
'bleConnectionSuccess'.tr,
|
|
'bleConnectedToDevice'.trParams({'device': device.platformName.isNotEmpty ? device.platformName : 'unknownEquipment'.tr}),
|
|
backgroundColor: Colors.green,
|
|
colorText: Colors.white,
|
|
);
|
|
} catch (e) {
|
|
errorMessage.value = 'bleConnectionFailedWithError'.trParams({'error': e.toString()});
|
|
Get.snackbar(
|
|
'connectionFailed'.tr,
|
|
e.toString(),
|
|
backgroundColor: Colors.red,
|
|
colorText: Colors.white,
|
|
);
|
|
}
|
|
}
|
|
|
|
// 断开连接
|
|
Future<void> disconnectDevice() async {
|
|
try {
|
|
if (connectedDevice.value != null) {
|
|
await connectedDevice.value!.disconnect();
|
|
connectedDevice.value = null;
|
|
|
|
Get.snackbar(
|
|
'bleDisconnected'.tr,
|
|
'bleDeviceDisconnected'.tr,
|
|
backgroundColor: Colors.orange,
|
|
colorText: Colors.white,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
errorMessage.value = 'bleDisconnectFailedWithError'.trParams({'error': e.toString()});
|
|
}
|
|
}
|
|
|
|
// 获取设备名称
|
|
String getDeviceName(fbp.ScanResult result) {
|
|
if (result.device.platformName.isNotEmpty) {
|
|
return result.device.platformName;
|
|
}
|
|
if (result.advertisementData.localName.isNotEmpty) {
|
|
return result.advertisementData.localName;
|
|
}
|
|
return 'unknownEquipment'.tr;
|
|
}
|
|
|
|
// 获取信号强度描述
|
|
String getSignalStrengthText(int rssi) {
|
|
if (rssi >= -50) return 'signalStrong'.tr;
|
|
if (rssi >= -70) return 'signalMedium'.tr;
|
|
if (rssi >= -90) return 'signalWeak'.tr;
|
|
return 'signalVeryWeak'.tr;
|
|
}
|
|
|
|
// 获取信号强度图标
|
|
IconData getSignalStrengthIcon(int rssi) {
|
|
if (rssi >= -50) return Icons.signal_wifi_4_bar;
|
|
if (rssi >= -70) return Icons.signal_wifi_4_bar;
|
|
if (rssi >= -90) return Icons.signal_wifi_4_bar;
|
|
return Icons.signal_wifi_4_bar;
|
|
}
|
|
}
|
|
|