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.
295 lines
9.2 KiB
295 lines
9.2 KiB
import 'dart:async';
|
|
import 'package:get/get.dart';
|
|
import '../../../core/routes/app_routes.dart';
|
|
import '../../../data/services/bluetooth_service.dart';
|
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart' hide BluetoothService;
|
|
import '../../../core/utils/logger.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
enum SearchStatus {
|
|
searching, // 正在搜索设备
|
|
found, // 找到设备
|
|
failed, // 搜索失败
|
|
noPermission, // 缺少权限
|
|
}
|
|
|
|
class PairingController extends GetxController {
|
|
// 搜索状态
|
|
final _searchStatus = SearchStatus.searching.obs;
|
|
SearchStatus get searchStatus => _searchStatus.value;
|
|
|
|
// 搜索动画的点
|
|
final _searchDots = ''.obs;
|
|
String get searchDots => _searchDots.value;
|
|
|
|
// 动画定时器
|
|
Timer? _animationTimer;
|
|
|
|
// 蓝牙服务
|
|
late BluetoothService _bluetoothService;
|
|
|
|
// 设备信息
|
|
final _deviceInfo = Rx<Map<String, dynamic>>({});
|
|
Map<String, dynamic> get deviceInfo => _deviceInfo.value;
|
|
|
|
// 蓝牙状态
|
|
final _isBluetoothAvailable = false.obs;
|
|
final _isBluetoothOn = false.obs;
|
|
bool get isBluetoothAvailable => _isBluetoothAvailable.value;
|
|
bool get isBluetoothOn => _isBluetoothOn.value;
|
|
|
|
// 错误消息
|
|
final _errorMessage = ''.obs;
|
|
String get errorMessage => _errorMessage.value;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
// 启动搜索动画
|
|
_startSearchingAnimation();
|
|
|
|
// 延迟初始化蓝牙服务,避免在应用启动时就请求权限
|
|
// 改为延迟初始化,给UI足够时间渲染
|
|
Future.delayed(const Duration(milliseconds: 500), () {
|
|
_initBluetoothService();
|
|
});
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_stopSearchingAnimation();
|
|
super.onClose();
|
|
}
|
|
|
|
// 初始化蓝牙服务
|
|
Future<void> _initBluetoothService() async {
|
|
try {
|
|
// 获取蓝牙服务实例
|
|
if (Get.isRegistered<BluetoothService>()) {
|
|
_bluetoothService = Get.find<BluetoothService>();
|
|
} else {
|
|
_bluetoothService = await Get.put(BluetoothService()).init();
|
|
}
|
|
|
|
// 监听蓝牙状态变化
|
|
ever(_bluetoothService.isAvailableObs, (bool available) {
|
|
_isBluetoothAvailable.value = available;
|
|
});
|
|
|
|
ever(_bluetoothService.isOnObs, (bool on) {
|
|
_isBluetoothOn.value = on;
|
|
|
|
// 如果蓝牙开启,开始扫描设备
|
|
if (on) {
|
|
// 延迟开始扫描,避免权限请求过早
|
|
Future.delayed(const Duration(milliseconds: 300), () {
|
|
_startScanningDevices();
|
|
});
|
|
} else {
|
|
_errorMessage.value = '请打开蓝牙以搜索设备';
|
|
_searchStatus.value = SearchStatus.failed;
|
|
_stopSearchingAnimation();
|
|
}
|
|
});
|
|
|
|
// 如果蓝牙已经开启,直接开始扫描
|
|
if (_bluetoothService.isOn) {
|
|
_isBluetoothOn.value = true;
|
|
// 延迟开始扫描,避免权限请求过早
|
|
Future.delayed(const Duration(milliseconds: 300), () {
|
|
_startScanningDevices();
|
|
});
|
|
} else {
|
|
_errorMessage.value = '请打开蓝牙以搜索设备';
|
|
}
|
|
} catch (e) {
|
|
Logger.error('初始化蓝牙服务失败: $e');
|
|
_errorMessage.value = '初始化蓝牙服务失败';
|
|
_searchStatus.value = SearchStatus.failed;
|
|
_stopSearchingAnimation();
|
|
}
|
|
}
|
|
|
|
// 启动搜索动画
|
|
void _startSearchingAnimation() {
|
|
_stopSearchingAnimation(); // 清除已有的定时器
|
|
|
|
int count = 0;
|
|
_animationTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
|
|
count = (count + 1) % 4;
|
|
_searchDots.value = '.' * count;
|
|
});
|
|
}
|
|
|
|
// 停止搜索动画
|
|
void _stopSearchingAnimation() {
|
|
_animationTimer?.cancel();
|
|
_animationTimer = null;
|
|
_searchDots.value = '';
|
|
}
|
|
|
|
// 请求必要权限
|
|
Future<bool> _requestPermissions() async {
|
|
// 暂时跳过权限检查,直接返回true
|
|
return true;
|
|
}
|
|
|
|
// 打开应用设置
|
|
void goToAppSettings() async {
|
|
try {
|
|
await openAppSettings();
|
|
} catch (e) {
|
|
Logger.error('打开应用设置失败: $e');
|
|
Get.snackbar(
|
|
'提示',
|
|
'无法打开应用设置,请手动打开系统设置授予权限',
|
|
snackPosition: SnackPosition.TOP,
|
|
backgroundColor: Colors.red[100],
|
|
colorText: Colors.red[800],
|
|
duration: const Duration(seconds: 3),
|
|
);
|
|
}
|
|
}
|
|
|
|
// 开始扫描蓝牙设备
|
|
Future<void> _startScanningDevices() async {
|
|
try {
|
|
// 先检查是否已有连接的设备
|
|
if (_bluetoothService.connectedDevices.isNotEmpty) {
|
|
// 有已连接的设备,直接使用
|
|
_deviceFound(_bluetoothService.connectedDevices.first);
|
|
return;
|
|
}
|
|
|
|
// 检查是否有已配对的设备
|
|
if (await _checkPairedDevices()) {
|
|
// 已找到并成功连接到配对设备
|
|
return;
|
|
}
|
|
|
|
// 搜索新设备
|
|
_searchStatus.value = SearchStatus.searching;
|
|
await _bluetoothService.startScan(timeout: const Duration(seconds: 10));
|
|
|
|
// 检查扫描结果
|
|
if (_bluetoothService.scanResults.isNotEmpty) {
|
|
// 找到设备,选择信号最强的一个
|
|
final strongestSignal = _bluetoothService.scanResults
|
|
.reduce((a, b) => (a.rssi > b.rssi) ? a : b);
|
|
|
|
// 连接设备
|
|
final success = await _bluetoothService.connectToDevice(strongestSignal.device);
|
|
|
|
if (success) {
|
|
_deviceFound(strongestSignal.device);
|
|
} else {
|
|
_errorMessage.value = '连接设备失败,请重试';
|
|
_searchStatus.value = SearchStatus.failed;
|
|
_stopSearchingAnimation();
|
|
}
|
|
} else {
|
|
// 未找到设备
|
|
_errorMessage.value = '未找到蓝牙设备,请确保设备已开启并在附近';
|
|
_searchStatus.value = SearchStatus.failed;
|
|
_stopSearchingAnimation();
|
|
}
|
|
} catch (e) {
|
|
Logger.error('扫描蓝牙设备失败: $e');
|
|
_errorMessage.value = '扫描蓝牙设备失败: ${e.toString()}';
|
|
_searchStatus.value = SearchStatus.failed;
|
|
_stopSearchingAnimation();
|
|
}
|
|
}
|
|
|
|
// 检查已配对设备
|
|
Future<bool> _checkPairedDevices() async {
|
|
try {
|
|
// 先检查当前是否有设备已连接
|
|
if (_bluetoothService.selectedDevice != null &&
|
|
_bluetoothService.connectionState == BluetoothConnectionState.connected) {
|
|
Logger.info('已有设备连接: ${_bluetoothService.selectedDevice!.platformName}');
|
|
_deviceFound(_bluetoothService.selectedDevice!);
|
|
return true;
|
|
}
|
|
|
|
List<BluetoothDevice> pairedDevices = await _bluetoothService.getPairedDevices();
|
|
if (pairedDevices.isEmpty) {
|
|
Logger.info('没有找到已配对设备');
|
|
return false;
|
|
}
|
|
|
|
// 遍历配对设备,检查是否有设备已连接
|
|
for (BluetoothDevice device in pairedDevices) {
|
|
try {
|
|
BluetoothConnectionState state = await device.connectionState.first;
|
|
if (state == BluetoothConnectionState.connected) {
|
|
Logger.info('发现已连接的设备: ${device.platformName}');
|
|
// 设置为当前设备但不需要连接
|
|
final success = await _bluetoothService.connectToDevice(device);
|
|
if (success) {
|
|
_deviceFound(device);
|
|
return true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// 忽略单个设备的连接状态检查错误,继续检查下一个
|
|
Logger.error('检查设备连接状态失败: $e');
|
|
}
|
|
}
|
|
|
|
// 如果没有找到已连接的设备,尝试连接第一个配对设备
|
|
Logger.info('尝试连接配对设备: ${pairedDevices.first.platformName}');
|
|
final success = await _bluetoothService.connectToDevice(pairedDevices.first);
|
|
|
|
if (success) {
|
|
_deviceFound(pairedDevices.first);
|
|
return true;
|
|
} else {
|
|
// 连接失败,继续搜索新设备
|
|
Logger.info('已配对设备连接失败,继续搜索新设备');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
Logger.error('检查已配对设备失败: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 设备被找到时的处理
|
|
void _deviceFound(BluetoothDevice device) {
|
|
_searchStatus.value = SearchStatus.found;
|
|
_stopSearchingAnimation();
|
|
|
|
// 获取设备信息
|
|
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo();
|
|
|
|
// 延迟后跳转到主页,同时传递设备信息
|
|
Timer(const Duration(seconds: 1), () {
|
|
Get.offAllNamed(Routes.home, arguments: _deviceInfo.value);
|
|
});
|
|
}
|
|
|
|
// 手动连接
|
|
void manualConnect() {
|
|
if (_searchStatus.value == SearchStatus.searching) {
|
|
// 如果正在搜索,则停止搜索
|
|
_bluetoothService.stopScan();
|
|
}
|
|
|
|
// 重新开始搜索
|
|
_startSearchingAnimation();
|
|
_searchStatus.value = SearchStatus.searching;
|
|
_startScanningDevices();
|
|
}
|
|
|
|
// 稍后再说
|
|
void skipConnecting() {
|
|
if (_searchStatus.value == SearchStatus.searching) {
|
|
// 如果正在搜索,则停止搜索
|
|
_bluetoothService.stopScan();
|
|
}
|
|
|
|
Get.offAllNamed(Routes.home);
|
|
}
|
|
}
|