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.1 KiB
281 lines
7.1 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 = '请开启蓝牙';
|
|
stopScan();
|
|
}
|
|
});
|
|
|
|
// 监听扫描结果
|
|
fbp.FlutterBluePlus.scanResults.listen((results) {
|
|
scanResults.value = results;
|
|
});
|
|
|
|
// 监听扫描状态
|
|
fbp.FlutterBluePlus.isScanning.listen((scanning) {
|
|
isScanning.value = scanning;
|
|
});
|
|
} catch (e) {
|
|
errorMessage.value = '蓝牙初始化失败: $e';
|
|
}
|
|
}
|
|
|
|
// 检查权限(不请求)
|
|
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 = '需要蓝牙和位置权限才能扫描设备';
|
|
}
|
|
} 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 = '需要蓝牙和位置权限才能扫描设备';
|
|
}
|
|
}
|
|
|
|
return allGranted;
|
|
} catch (e) {
|
|
print('请求权限失败: $e');
|
|
errorMessage.value = '权限请求失败: $e';
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 显示权限对话框
|
|
void _showPermissionDialog() {
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text('需要权限'),
|
|
content: Text('应用需要蓝牙和位置权限才能扫描设备。请在设置中手动开启权限。'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text('取消'),
|
|
),
|
|
TextButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
AppSettings.openAppSettings();
|
|
},
|
|
child: Text('去设置'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 显示蓝牙开启对话框
|
|
void _showBluetoothDialog() {
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text('需要开启蓝牙'),
|
|
content: Text('请开启蓝牙以扫描和连接设备。'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text('取消'),
|
|
),
|
|
TextButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
// 尝试开启蓝牙
|
|
fbp.FlutterBluePlus.turnOn();
|
|
},
|
|
child: Text('开启蓝牙'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 开始扫描
|
|
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 = '扫描失败: $e';
|
|
}
|
|
}
|
|
|
|
// 停止扫描
|
|
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(
|
|
'连接成功',
|
|
'已连接到 ${device.platformName.isNotEmpty ? device.platformName : '未知设备'}',
|
|
backgroundColor: Colors.green,
|
|
colorText: Colors.white,
|
|
);
|
|
} catch (e) {
|
|
errorMessage.value = '连接失败: $e';
|
|
Get.snackbar(
|
|
'连接失败',
|
|
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(
|
|
'已断开连接',
|
|
'设备已断开连接',
|
|
backgroundColor: Colors.orange,
|
|
colorText: Colors.white,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
errorMessage.value = '断开连接失败: $e';
|
|
}
|
|
}
|
|
|
|
// 获取设备名称
|
|
String getDeviceName(fbp.ScanResult result) {
|
|
if (result.device.platformName.isNotEmpty) {
|
|
return result.device.platformName;
|
|
}
|
|
if (result.advertisementData.localName.isNotEmpty) {
|
|
return result.advertisementData.localName;
|
|
}
|
|
return '未知设备';
|
|
}
|
|
|
|
// 获取信号强度描述
|
|
String getSignalStrengthText(int rssi) {
|
|
if (rssi >= -50) return '信号强';
|
|
if (rssi >= -70) return '信号中等';
|
|
if (rssi >= -90) return '信号弱';
|
|
return '信号很弱';
|
|
}
|
|
|
|
// 获取信号强度图标
|
|
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;
|
|
}
|
|
}
|
|
|