Browse Source

bluteeth

weicu
wolfplus 2 years ago
parent
commit
13003cd286
  1. 30
      android/app/src/main/kotlin/com/example/deep_voice/MainActivity.kt
  2. 302
      lib/data/services/bluetooth_service.dart
  3. 7
      lib/modules/chat/controllers/chat_controller.dart
  4. 991
      lib/modules/chat/views/chat_view.dart
  5. 77
      lib/modules/explore/controllers/explore_controller.dart
  6. 365
      lib/modules/home/controllers/home_controller.dart
  7. 160
      lib/modules/pairing/controllers/pairing_controller.dart

30
android/app/src/main/kotlin/com/example/deep_voice/MainActivity.kt

@ -71,7 +71,7 @@ class MainActivity: FlutterActivity() {
// Azure 语音服务配置
var azureSpeechKey: String = "2K2VOHSuL8ZSEnbKgHSyTwo1ohj7C2gbxyVimsjpVUt6aETxVwlvJQQJ99BCACqBBLyXJ3w3AAAYACOGqCMj"
var azureSpeechRegion: String = "southeastasia"
var volcanoAiApiKey: String = "0fd7c93b-b9bf-4b0b-bca6-e284491792bf"
var volcanoAiApiKey: String = "168deb3d-fd0c-4912-b9f1-aaee5c6743e6"
// 标记是否已初始化
var isAzureHelpersInitialized = false
@ -158,20 +158,20 @@ class MainActivity: FlutterActivity() {
events?.success(mapOf("type" to "channelReady"))
Log.d(TAG, "已发送 channelReady 事件")
// 测试发送一个聊天记录事件
Handler(Looper.getMainLooper()).postDelayed({
if (voiceInteractionEventSink != null) {
Log.d(TAG, "发送测试聊天记录事件")
sendChatHistoryEvent(
"personal_assistant",
"这是一条测试用户消息",
"这是一条测试助手回复",
System.currentTimeMillis()
)
} else {
Log.e(TAG, "无法发送测试事件:事件通道未准备好")
}
}, 5000) // 5秒后发送测试事件
// // 测试发送一个聊天记录事件
// Handler(Looper.getMainLooper()).postDelayed({
// if (voiceInteractionEventSink != null) {
// Log.d(TAG, "发送测试聊天记录事件")
// sendChatHistoryEvent(
// "personal_assistant",
// "这是一条测试用户消息",
// "这是一条测试助手回复",
// System.currentTimeMillis()
// )
// } else {
// Log.e(TAG, "无法发送测试事件:事件通道未准备好")
// }
// }, 5000) // 5秒后发送测试事件
} catch (e: Exception) {
Log.e(TAG, "发送 channelReady 事件失败: ${e.message}", e)
}

302
lib/data/services/bluetooth_service.dart

@ -34,6 +34,9 @@ class BluetoothService extends GetxService {
// 连接状态
final _connectionState = Rx<BluetoothConnectionState>(BluetoothConnectionState.disconnected);
// 存储最后连接的设备信息,供其他控制器使用
final _lastConnectedDeviceInfo = Rx<Map<String, dynamic>>({});
// 订阅
StreamSubscription? _stateSubscription;
StreamSubscription? _scanSubscription;
@ -51,6 +54,7 @@ class BluetoothService extends GetxService {
List<ScanResult> get scanResults => _scanResults;
BluetoothDevice? get selectedDevice => _selectedDevice.value;
BluetoothConnectionState get connectionState => _connectionState.value;
Map<String, dynamic> get lastConnectedDeviceInfo => _lastConnectedDeviceInfo.value;
// Observable getters (for reactive programming)
RxBool get isAvailableObs => _isAvailable;
@ -59,6 +63,7 @@ class BluetoothService extends GetxService {
RxList<ScanResult> get scanResultsObs => _scanResults;
Rx<BluetoothDevice?> get selectedDeviceObs => _selectedDevice;
Rx<BluetoothConnectionState> get connectionStateObs => _connectionState;
Rx<Map<String, dynamic>> get lastConnectedDeviceInfoObs => _lastConnectedDeviceInfo;
/// 初始化蓝牙服务
Future<BluetoothService> init() async {
@ -66,29 +71,50 @@ class BluetoothService extends GetxService {
// 不在初始化时检查权限,改为在需要时才检查
// await _checkAndRequestPermissions();
// 监听蓝牙状态
_stateSubscription = FlutterBluePlus.adapterState.listen((state) {
_isOn.value = state == BluetoothAdapterState.on;
_isAvailable.value = state != BluetoothAdapterState.unavailable;
if (state == BluetoothAdapterState.on) {
// 蓝牙打开时,获取已连接设备,但不请求权限
// 只有在用户主动扫描时才请求权限
_getConnectedDevices();
} else if (state == BluetoothAdapterState.off) {
// 蓝牙关闭时,清空设备列表
_connectedDevices.clear();
_scanResults.clear();
_selectedDevice.value = null;
}
// 在后台线程初始化蓝牙状态监听,避免主线程阻塞
Future.microtask(() {
// 监听蓝牙状态
_stateSubscription = FlutterBluePlus.adapterState.listen((state) {
_isOn.value = state == BluetoothAdapterState.on;
_isAvailable.value = state != BluetoothAdapterState.unavailable;
if (state == BluetoothAdapterState.on) {
// 蓝牙打开时,获取已连接设备,但不请求权限
// 只有在用户主动扫描时才请求权限
// 在后台线程执行,避免主线程阻塞
Future.microtask(() => _getConnectedDevices());
} else if (state == BluetoothAdapterState.off) {
// 蓝牙关闭时,清空设备列表
_connectedDevices.clear();
_scanResults.clear();
_selectedDevice.value = null;
_lastConnectedDeviceInfo.value = {};
}
});
});
// 检查当前蓝牙状态,如果已开启则获取设备
if (await FlutterBluePlus.isOn) {
_isOn.value = true;
_isAvailable.value = true;
_getConnectedDevices();
}
// 不在初始化时立即检查蓝牙状态,而是延迟到UI渲染完成后
// 这样可以避免启动时卡顿
Future.delayed(const Duration(milliseconds: 800), () async {
try {
// 使用超时机制,避免无限等待蓝牙
bool isOn = await FlutterBluePlus.isOn
.timeout(const Duration(seconds: 3), onTimeout: () {
Logger.error('检查蓝牙状态超时');
return false;
});
_isOn.value = isOn;
_isAvailable.value = isOn;
if (isOn) {
// 在后台线程获取设备,避免主线程阻塞
Future.microtask(() => _getConnectedDevices());
}
} catch (e) {
Logger.error('延迟检查蓝牙状态失败: $e');
}
});
return this;
} catch (e) {
@ -114,14 +140,21 @@ class BluetoothService extends GetxService {
/// 获取已连接的设备
Future<void> _getConnectedDevices() async {
try {
// 获取已连接的设备
List<BluetoothDevice> devices = await FlutterBluePlus.connectedSystemDevices;
// 使用超时机制,避免无限等待
List<BluetoothDevice> devices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 3), onTimeout: () {
Logger.error('获取已连接设备超时');
return <BluetoothDevice>[];
});
_connectedDevices.value = devices;
// 如果有已连接的设备但没有选中设备,则选中第一个
if (_connectedDevices.isNotEmpty && _selectedDevice.value == null) {
_selectedDevice.value = _connectedDevices[0];
_monitorConnectionState(_selectedDevice.value!);
// 更新最后连接的设备信息
_updateLastConnectedDeviceInfo();
}
Logger.info('已连接设备数量: ${_connectedDevices.length}');
@ -142,15 +175,17 @@ class BluetoothService extends GetxService {
}
}
/// 开始扫描附近的蓝牙设备
Future<void> startScan({Duration? timeout}) async {
if (_isScanning.value) return;
/// 开始扫描附近的蓝牙设备并尝试连接最强信号设备
Future<BluetoothDevice?> scanAndConnectToDevice({Duration? timeout}) async {
if (_isScanning.value) {
await stopScan();
}
// 清空旧的扫描结果
_scanResults.clear();
try {
// 开始扫描
// 设置扫描监听
_scanSubscription?.cancel();
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults.value = results;
@ -161,16 +196,34 @@ class BluetoothService extends GetxService {
// 开始扫描
await FlutterBluePlus.startScan(
timeout: timeout ?? const Duration(seconds: 10),
timeout: timeout ?? const Duration(seconds: 5),
);
// 扫描完成后更新状态
// 扫描完成
_isScanning.value = false;
Logger.info('蓝牙扫描完成,发现 ${_scanResults.length} 个设备');
// 如果找到设备,尝试连接信号最强的
if (_scanResults.isNotEmpty) {
// 按信号强度排序
List<ScanResult> sortedResults = List.from(_scanResults);
sortedResults.sort((a, b) => b.rssi.compareTo(a.rssi));
// 尝试连接信号最强的设备
final topDevice = sortedResults.first.device;
Logger.info('尝试连接信号最强的设备: ${topDevice.platformName}');
bool success = await connectToDevice(topDevice);
if (success) {
return topDevice;
}
}
return null;
} catch (e) {
_isScanning.value = false;
Logger.error('蓝牙扫描失败: $e');
Logger.error('蓝牙扫描或连接失败: $e');
return null;
}
}
@ -186,66 +239,56 @@ class BluetoothService extends GetxService {
}
}
/// 连接到指定设备
/// 连接到指定的蓝牙设备 - 简化版本
Future<bool> connectToDevice(BluetoothDevice device) async {
if (_selectedDevice.value == device) {
// 如果是当前选中设备,检查连接状态
if (_connectionState.value == BluetoothConnectionState.connected) {
Logger.info('设备 ${device.platformName} 已经连接,无需重新连接');
return true;
}
}
Logger.info('尝试连接设备: ${device.platformName} (${device.remoteId.str})');
try {
// 检查设备是否已连接
bool isAlreadyConnected = false;
// 检查设备连接状态
BluetoothConnectionState state = await device.connectionState.first;
if (state == BluetoothConnectionState.connected) {
Logger.info('设备 ${device.platformName} 已处于连接状态');
isAlreadyConnected = true;
}
// 如果设备已连接,直接更新状态而不尝试连接
if (isAlreadyConnected) {
// 断开当前跟踪的设备(如果有)
if (_selectedDevice.value != null && _selectedDevice.value != device) {
_connectionSubscription?.cancel();
}
// 更新状态
_selectedDevice.value = device;
_monitorConnectionState(device);
// 如果是当前已连接设备,直接返回成功
if (_selectedDevice.value == device &&
_connectionState.value == BluetoothConnectionState.connected) {
Logger.info('设备已连接,无需重新连接');
return true;
}
// 断开当前连接
await disconnectFromDevice();
if (_selectedDevice.value != null && _selectedDevice.value != device) {
await disconnectFromDevice();
}
// 连接新设备
// 直接尝试连接
Logger.info('直接连接设备 ${device.platformName}');
await device.connect();
// 更新状态
// 更新设备信息
_selectedDevice.value = device;
_monitorConnectionState(device);
_updateLastConnectedDeviceInfo();
Logger.info('设备 ${device.platformName} 连接成功');
return true;
} catch (e) {
Logger.error('连接蓝牙设备失败: $e');
Logger.error('连接设备 ${device.platformName} 失败: $e');
return false;
}
}
/// 断开与当前设备的连接
Future<bool> disconnectFromDevice() async {
if (_selectedDevice.value == null) return true;
if (_selectedDevice.value == null) {
Logger.info('没有当前选中的设备,无需断开连接');
return true;
}
try {
Logger.info('正在断开设备 ${_selectedDevice.value!.platformName} 的连接');
await _selectedDevice.value!.disconnect();
Logger.info('设备连接已断开,取消连接状态监听');
_connectionSubscription?.cancel();
_connectionSubscription = null;
_selectedDevice.value = null;
// 清除最后连接的设备信息
_lastConnectedDeviceInfo.value = {};
return true;
} catch (e) {
@ -256,14 +299,35 @@ class BluetoothService extends GetxService {
/// 监控连接状态
void _monitorConnectionState(BluetoothDevice device) {
_connectionSubscription?.cancel();
Logger.info('设置设备 ${device.platformName} 的连接状态监听');
// 取消之前的监听
if (_connectionSubscription != null) {
Logger.info('取消之前的连接状态监听');
_connectionSubscription!.cancel();
_connectionSubscription = null;
}
// 设置新的监听
_connectionSubscription = device.connectionState.listen((state) {
Logger.info('设备 ${device.platformName} 连接状态变更为: $state');
_connectionState.value = state;
if (state == BluetoothConnectionState.disconnected) {
Logger.info('设备 ${device.platformName} 已断开连接');
_selectedDevice.value = null;
// 设备断开连接时,不清除最后连接的设备信息,以便下次可以重新连接
} else if (state == BluetoothConnectionState.connected) {
Logger.info('设备 ${device.platformName} 已成功连接');
// 设备连接成功时,更新最后连接的设备信息
_updateLastConnectedDeviceInfo();
} else if (state == BluetoothConnectionState.connecting) {
Logger.info('设备 ${device.platformName} 正在连接中...');
} else if (state == BluetoothConnectionState.disconnecting) {
Logger.info('设备 ${device.platformName} 正在断开连接...');
}
});
Logger.info('设备 ${device.platformName} 的连接状态监听已设置');
}
/// 获取已连接设备的信息
@ -275,7 +339,7 @@ class BluetoothService extends GetxService {
};
}
return {
final deviceInfo = {
'connected': _connectionState.value == BluetoothConnectionState.connected,
'device': {
'name': _selectedDevice.value!.platformName.isEmpty ?
@ -287,6 +351,112 @@ class BluetoothService extends GetxService {
?.rssi
}
};
// 更新最后连接的设备信息
_lastConnectedDeviceInfo.value = deviceInfo;
return deviceInfo;
}
/// 更新最后连接的设备信息
void _updateLastConnectedDeviceInfo() {
if (_selectedDevice.value != null) {
_lastConnectedDeviceInfo.value = {
'connected': _connectionState.value == BluetoothConnectionState.connected,
'device': {
'name': _selectedDevice.value!.platformName.isEmpty ?
'未命名设备' : _selectedDevice.value!.platformName,
'id': _selectedDevice.value!.remoteId.str,
'isConnected': _connectionState.value == BluetoothConnectionState.connected,
'rssi': _scanResults
.firstWhereOrNull((r) => r.device.remoteId == _selectedDevice.value!.remoteId)
?.rssi
}
};
}
}
/// 一个综合方法,执行自动查找并连接设备的完整流程
Future<BluetoothDevice?> autoConnectDevice() async {
try {
// 1. 先检查当前已连接设备
if (_selectedDevice.value != null &&
_connectionState.value == BluetoothConnectionState.connected) {
Logger.info('使用当前已连接设备: ${_selectedDevice.value!.platformName}');
return _selectedDevice.value;
}
// 2. 检查系统中已连接的设备
try {
List<BluetoothDevice> connectedDevices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 3));
if (connectedDevices.isNotEmpty) {
// 有已连接的设备,直接使用第一个
Logger.info('发现系统已连接设备: ${connectedDevices.first.platformName}');
// 连接设备并更新服务状态
await connectToDevice(connectedDevices.first);
return connectedDevices.first;
}
} catch (e) {
Logger.error('检查系统连接设备失败: $e');
}
// 3. 尝试连接之前用过的设备(从已配对设备中寻找)
List<BluetoothDevice> pairedDevices = await FlutterBluePlus.bondedDevices;
// 如果有配对设备,尝试连接第一个
if (pairedDevices.isNotEmpty) {
Logger.info('尝试连接已配对设备: ${pairedDevices.first.platformName}');
bool success = await connectToDevice(pairedDevices.first);
if (success) {
return pairedDevices.first;
}
}
// 4. 没有找到可用设备
return null;
} catch (e) {
Logger.error('自动连接设备流程失败: $e');
return null;
}
}
/// 获取设备连接状态的简化方法 (用于兼容现有代码)
Future<BluetoothConnectionState> getReliableConnectionState(BluetoothDevice device) async {
try {
// 直接获取设备当前状态
BluetoothConnectionState state = await device.connectionState.first
.timeout(const Duration(seconds: 2), onTimeout: () {
Logger.info('获取设备 ${device.platformName} 连接状态超时');
return BluetoothConnectionState.disconnected;
});
// 如果获取到的状态是已连接,直接返回
if (state == BluetoothConnectionState.connected) {
return BluetoothConnectionState.connected;
}
// 作为备用检查,看设备是否在系统已连接列表中
try {
List<BluetoothDevice> connectedDevices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 2));
for (var connectedDevice in connectedDevices) {
if (connectedDevice.remoteId.str == device.remoteId.str) {
return BluetoothConnectionState.connected;
}
}
} catch (e) {
// 忽略检查系统设备列表的错误
}
return state;
} catch (e) {
Logger.error('获取设备 ${device.platformName} 连接状态失败: $e');
return BluetoothConnectionState.disconnected;
}
}
@override

7
lib/modules/chat/controllers/chat_controller.dart

@ -257,6 +257,8 @@ class ChatController extends GetxController {
Future<void> sendMessage(String text) async {
if (text.trim().isEmpty) return;
_voiceInteractionService.pauseVoiceInteraction();
// 中断当前响应
_interruptCurrentResponse("发送新消息,中断当前响应");
@ -419,7 +421,8 @@ class ChatController extends GetxController {
// 初始化语音识别
await _asrService.initialize(language: 'zh-CN');
// 启动连续语音识别
// 启动连续语音识别
// 注意:在UI更新后,使用模拟波形动画替代实际麦克风输入的波形数据
final recognitionStream = await _asrService.startContinuousRecognition();
isVoiceRecognitionActive.value = true;
@ -429,6 +432,8 @@ class ChatController extends GetxController {
// 重置临时消息索引
_tempMessageIndex = -1;
// 监听识别事件
_recognitionSubscription = recognitionStream.listen(
_handleRecognitionEvent,

991
lib/modules/chat/views/chat_view.dart

File diff suppressed because it is too large

77
lib/modules/explore/controllers/explore_controller.dart

@ -1,5 +1,7 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import '../../../data/providers/agent_provider.dart';
import '../../../core/routes/app_routes.dart';
class AIFeature {
final String title;
@ -9,6 +11,8 @@ class AIFeature {
final Color endColor;
final Color iconBgColor;
final Color iconColor;
final String agentId;
final String targetRoute;
AIFeature({
required this.title,
@ -18,6 +22,8 @@ class AIFeature {
required this.endColor,
required this.iconBgColor,
required this.iconColor,
required this.agentId,
required this.targetRoute,
});
}
@ -46,13 +52,26 @@ class ExploreController extends GetxController {
// AI功能列表
final List<AIFeature> aiFeatures = [
AIFeature(
title: '同声翻译',
description: '实时翻译40+种语言',
icon: Icons.translate,
title: '全能助理',
description: '帮你解决各类问题',
icon: Icons.assistant,
startColor: Colors.blue.shade100,
endColor: Colors.blue.shade200,
iconBgColor: Colors.blue.withOpacity(0.2),
iconColor: Colors.blue.shade600,
agentId: 'personal_assistant',
targetRoute: Routes.chat,
),
AIFeature(
title: '同声翻译',
description: '实时翻译40+种语言',
icon: Icons.translate,
startColor: Colors.green.shade100,
endColor: Colors.green.shade200,
iconBgColor: Colors.green.withOpacity(0.2),
iconColor: Colors.green.shade600,
agentId: 'simultaneous_interpreter',
targetRoute: Routes.translation,
),
AIFeature(
title: 'AI女友',
@ -62,24 +81,19 @@ class ExploreController extends GetxController {
endColor: Colors.pink.shade200,
iconBgColor: Colors.pink.withOpacity(0.2),
iconColor: Colors.pink.shade600,
agentId: 'cyber_girlfriend',
targetRoute: Routes.chat,
),
AIFeature(
title: '音乐创作',
description: '用AI创作专属音乐',
icon: Icons.music_note,
startColor: Colors.green.shade100,
endColor: Colors.green.shade200,
iconBgColor: Colors.green.withOpacity(0.2),
iconColor: Colors.green.shade600,
),
AIFeature(
title: '声音克隆',
description: '创建你的数字声音',
icon: Icons.mic,
title: '健康顾问',
description: '提供科学健康建议',
icon: Icons.healing,
startColor: Colors.amber.shade100,
endColor: Colors.amber.shade200,
iconBgColor: Colors.amber.withOpacity(0.2),
iconColor: Colors.amber.shade600,
agentId: 'health_advisor',
targetRoute: Routes.chat,
),
];
@ -129,13 +143,34 @@ class ExploreController extends GetxController {
void onAIFeatureTap(int index) {
if (index < 0 || index >= aiFeatures.length) return;
Get.snackbar(
'功能',
'您选择了: ${aiFeatures[index].title}',
snackPosition: SnackPosition.TOP,
);
final feature = aiFeatures[index];
final agent = AgentProvider.getAgentById(feature.agentId);
if (agent == null) {
Get.snackbar(
'错误',
'未找到对应的AI助手',
snackPosition: SnackPosition.TOP,
);
return;
}
// 实际应用中,这里应该跳转到对应的功能页面
// 根据目标路由进行跳转
if (feature.targetRoute == Routes.chat) {
// 跳转到聊天页面
Get.toNamed(feature.targetRoute, arguments: {
'agentId': agent.id,
'agentName': agent.name,
'agentVoice': agent.voice,
'agentAvatar': agent.avatarUrl,
'agentSubtitle': agent.description,
'systemPrompt': agent.systemPrompt,
'welcomeMessage': agent.welcomeMessage,
});
} else if (feature.targetRoute == Routes.translation) {
// 跳转到翻译页面
Get.toNamed(feature.targetRoute);
}
}
// 点击功能场景

365
lib/modules/home/controllers/home_controller.dart

@ -4,7 +4,7 @@ import '../../../data/services/bluetooth_service.dart';
import '../../../core/utils/logger.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart' hide BluetoothService;
import 'package:flutter/material.dart';
import '../../../data/services/voice_interaction_service.dart';
// 连接状态枚举
enum ConnectionStatus {
disconnected, // 未连接
@ -50,17 +50,70 @@ class HomeController extends GetxController {
@override
void onInit() {
super.onInit();
// 检查是否有传入的蓝牙设备信息
if (Get.arguments != null && Get.arguments is Map<String, dynamic>) {
_deviceInfo.assignAll(Get.arguments);
_updateConnectionStatus();
}
// 获取蓝牙服务
_initBluetoothService();
// 立即加载缓存的设备信息并显示
_loadCachedDeviceInfo();
// 模拟定期获取电池状态
_simulateBatteryUpdates();
// 先进行简单初始化,避免立即进行蓝牙操作
_initBasicServices();
// 延迟初始化蓝牙相关功能,让UI先渲染完成
Future.delayed(const Duration(milliseconds: 1200), () {
_initBluetoothService();
});
}
// 立即加载缓存的设备信息
void _loadCachedDeviceInfo() {
try {
// 1. 首先检查是否有传入的设备信息(从PairingController传入)
if (Get.arguments != null && Get.arguments is Map<String, dynamic>) {
Logger.info('使用传入的设备信息');
_deviceInfo.assignAll(Get.arguments);
_updateConnectionStatus();
update(); // 立即更新UI
return;
}
// 2. 如果没有传入信息,尝试从BluetoothService获取上次连接的设备信息
if (Get.isRegistered<BluetoothService>()) {
BluetoothService bluetoothService = Get.find<BluetoothService>();
if (bluetoothService.lastConnectedDeviceInfo.isNotEmpty) {
Logger.info('使用BluetoothService中存储的上次连接设备信息');
_deviceInfo.assignAll(bluetoothService.lastConnectedDeviceInfo);
_updateConnectionStatus();
update(); // 立即更新UI
return;
}
}
// 3. 如果上述都没有,显示未连接状态
Logger.info('没有找到缓存的设备信息,显示未连接状态');
_connectionStatus.value = ConnectionStatus.disconnected;
_isConnected.value = false;
update(); // 立即更新UI
} catch (e) {
Logger.error('加载缓存设备信息失败: $e');
}
}
// 基础服务初始化,不涉及蓝牙等耗时操作
void _initBasicServices() {
try {
// 初始化语音交互
Future.microtask(() => VoiceInteractionService.to.initialize());
// 检查是否有传入的蓝牙设备信息
if (Get.arguments != null && Get.arguments is Map<String, dynamic>) {
_deviceInfo.assignAll(Get.arguments);
_updateConnectionStatus();
}
// 模拟电池状态更新(不涉及设备通信)
_simulateBatteryUpdates();
} catch (e) {
Logger.error('初始化基础服务失败: $e');
}
}
// 初始化蓝牙服务
@ -69,52 +122,220 @@ class HomeController extends GetxController {
if (Get.isRegistered<BluetoothService>()) {
_bluetoothService = Get.find<BluetoothService>();
// 如果已经有连接的设备但没有设备信息
if (_deviceInfo.isEmpty && _bluetoothService!.selectedDevice != null) {
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_updateConnectionStatus();
} else if (_deviceInfo.isEmpty) {
// 如果没有设备信息,尝试获取已配对设备
_checkPairedDevices();
}
// 不再重复加载设备信息,因为已经在_loadCachedDeviceInfo中加载过了
// 只进行状态同步
// 主动检查当前连接状态并更新
_checkAndUpdateCurrentConnectionState();
// 监听连接状态变化
ever(_bluetoothService!.connectionStateObs, (state) {
Logger.info('蓝牙连接状态变化: $state');
_processConnectionStateChange(state);
});
// 监听选中设备变化
ever(_bluetoothService!.selectedDeviceObs, (device) {
Logger.info('蓝牙选中设备变化: ${device?.platformName ?? "无设备"}');
if (device != null) {
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_updateConnectionStatus();
// 通知UI刷新
update();
} else if (_isConnected.value) {
// 如果设备断开连接,更新状态
_isConnected.value = false;
_deviceInfo.clear();
// 不清除设备信息,以便可以显示上次连接的设备
_connectionStatus.value = ConnectionStatus.disconnected;
// 通知UI刷新
update();
}
});
// 监听最后连接的设备信息变化
ever(_bluetoothService!.lastConnectedDeviceInfoObs, (info) {
Logger.info('最后连接的设备信息变化');
if (info.isNotEmpty) {
// 只有当设备信息为空或者连接状态不是已连接时,才更新设备信息
if (_deviceInfo.isEmpty || _connectionStatus.value != ConnectionStatus.connected) {
_deviceInfo.assignAll(info);
_updateConnectionStatus();
// 通知UI刷新
update();
}
}
});
// 如果当前没有连接状态,但有设备信息,尝试在后台重新连接
if (_connectionStatus.value != ConnectionStatus.connected &&
_deviceInfo.isNotEmpty &&
_deviceInfo['device'] != null &&
_deviceInfo['device']['id'] != null) {
// 延迟后台尝试连接设备,不阻塞UI
Future.delayed(const Duration(milliseconds: 2000), () {
_reconnectToLastDevice();
});
}
// 如果没有设备信息,延迟尝试获取已配对设备
else if (_deviceInfo.isEmpty) {
// 这个操作放在最后并延迟执行,因为它可能会触发蓝牙扫描
Future.delayed(const Duration(milliseconds: 2500), () {
_checkPairedDevices();
});
}
}
} catch (e) {
Logger.error('获取蓝牙服务失败: $e');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '获取蓝牙服务失败';
// 通知UI刷新
update();
}
}
// 检查并更新当前连接状态
void _checkAndUpdateCurrentConnectionState() {
if (_bluetoothService != null && _bluetoothService!.selectedDevice != null) {
// 如果有选择的设备,使用可靠方法获取一次状态
_bluetoothService!.getReliableConnectionState(_bluetoothService!.selectedDevice!).then((state) {
Logger.info('主动检查设备连接状态: $state');
_processConnectionStateChange(state);
}).catchError((e) {
Logger.error('检查连接状态失败: $e');
});
}
}
// 后台尝试重新连接到上次的设备
Future<void> _reconnectToLastDevice() async {
try {
Logger.info('尝试重新连接到上次的设备');
_connectionStatus.value = ConnectionStatus.connecting;
update(); // 立即更新UI显示连接中状态
// 使用超时机制,防止无响应
return await Future.sync(() async {
// 获取设备ID
String deviceId = _deviceInfo['device']['id'];
Logger.info('上次连接的设备ID: $deviceId');
// 获取已配对设备,使用超时保护
Logger.info('开始获取系统已配对设备列表...');
List<BluetoothDevice> pairedDevices = await _bluetoothService!.getPairedDevices()
.timeout(const Duration(seconds: 5), onTimeout: () {
Logger.error('获取已配对设备超时');
return <BluetoothDevice>[];
});
// 记录配对设备
if (pairedDevices.isNotEmpty) {
Logger.info('发现 ${pairedDevices.length} 个已配对设备:');
for (var i = 0; i < pairedDevices.length; i++) {
Logger.info('配对设备 #$i: ${pairedDevices[i].platformName ?? "未命名设备"} (${pairedDevices[i].remoteId.str})');
}
} else {
Logger.info('未找到任何已配对设备');
}
// 查找匹配ID的设备
Logger.info('开始查找匹配ID的设备: $deviceId');
BluetoothDevice? targetDevice;
for (var device in pairedDevices) {
Logger.info('检查设备 ${device.platformName ?? "未命名设备"} (${device.remoteId.str}) 是否匹配');
if (device.remoteId.str == deviceId) {
Logger.info('找到匹配ID的设备: ${device.platformName ?? "未命名设备"}');
targetDevice = device;
break;
}
}
// 如果找到目标设备,尝试连接
if (targetDevice != null) {
Logger.info('找到目标设备: ${targetDevice.platformName ?? "未命名设备"},尝试连接');
// 直接尝试连接设备,不做复杂状态检查
Logger.info('开始连接设备 ${targetDevice?.platformName ?? "未命名设备"}');
final success = await _bluetoothService!.connectToDevice(targetDevice)
.timeout(const Duration(seconds: 5), onTimeout: () {
Logger.error('连接设备 ${targetDevice?.platformName ?? "未命名设备"} 超时');
return false;
});
if (success) {
Logger.info('重新连接到设备 ${targetDevice?.platformName ?? "未命名设备"} 成功');
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_connectionStatus.value = ConnectionStatus.connected;
_isConnected.value = true;
_updateConnectionStatus();
update(); // 立即更新UI
} else {
Logger.error('重新连接到设备 ${targetDevice?.platformName ?? "未命名设备"} 失败');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '重新连接设备失败,请手动刷新或重新连接';
update(); // 立即更新UI
}
} else {
Logger.info('未找到匹配ID的设备,尝试连接第一个配对设备');
// 如果没有找到目标设备但有其他配对设备,尝试连接第一个
if (pairedDevices.isNotEmpty) {
var firstDevice = pairedDevices.first;
Logger.info('尝试连接第一个配对设备: ${firstDevice.platformName ?? "未命名设备"}');
// 直接尝试连接设备
Logger.info('开始连接设备 ${firstDevice.platformName ?? "未命名设备"}');
final success = await _bluetoothService!.connectToDevice(firstDevice)
.timeout(const Duration(seconds: 5), onTimeout: () {
Logger.error('连接设备 ${firstDevice.platformName ?? "未命名设备"} 超时');
return false;
});
if (success) {
Logger.info('自动连接到已配对设备成功: ${firstDevice.platformName ?? "未命名设备"}');
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_connectionStatus.value = ConnectionStatus.connected;
_isConnected.value = true; // 直接设置连接状态
_updateConnectionStatus();
update(); // 立即更新UI
} else {
Logger.error('连接到第一个配对设备 ${firstDevice.platformName ?? "未命名设备"} 失败');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '连接设备失败,请重试';
update(); // 立即更新UI
}
} else {
Logger.info('没有找到任何可用的配对设备');
_connectionStatus.value = ConnectionStatus.disconnected;
update(); // 立即更新UI
}
}
}).timeout(const Duration(seconds: 15), onTimeout: () {
Logger.error('重新连接设备整体流程超时');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '连接超时,请手动刷新或重新连接';
update(); // 立即更新UI
});
} catch (e) {
Logger.error('重新连接到设备失败: $e');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '连接失败,请手动刷新或重新连接';
update(); // 立即更新UI
}
}
// 处理连接状态变化
void _processConnectionStateChange(BluetoothConnectionState state) {
// 强制从蓝牙服务获取最新设备信息
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
switch (state) {
case BluetoothConnectionState.connected:
_connectionStatus.value = ConnectionStatus.connected;
_connectionErrorMsg.value = '';
_showConnectionSuccessMessage();
_isConnected.value = true; // 直接设置连接状态为true
// _showConnectionSuccessMessage();
break;
case BluetoothConnectionState.disconnected:
_connectionStatus.value = ConnectionStatus.disconnected;
_isConnected.value = false; // 直接设置连接状态为false
break;
case BluetoothConnectionState.connecting:
_connectionStatus.value = ConnectionStatus.connecting;
@ -124,7 +345,11 @@ class HomeController extends GetxController {
break;
}
_updateConnectionStatus();
// 延迟一帧后刷新状态,确保UI能更新
Future.microtask(() => _updateConnectionStatus());
// 通知UI刷新
update();
}
// 显示连接成功消息
@ -147,70 +372,81 @@ class HomeController extends GetxController {
Future<void> _checkPairedDevices() async {
try {
if (_bluetoothService != null) {
Logger.info('开始检查已配对设备流程');
// 更新状态为正在连接
_connectionStatus.value = ConnectionStatus.connecting;
update(); // 立即更新UI
// 如果已有选中的设备并且已连接,直接使用
if (_bluetoothService!.selectedDevice != null &&
_bluetoothService!.connectionState == BluetoothConnectionState.connected) {
Logger.info('使用已连接的设备: ${_bluetoothService!.selectedDevice!.platformName}');
Logger.info('使用已连接的设备: ${_bluetoothService!.selectedDevice!.platformName}, 连接状态: ${_bluetoothService!.connectionState}');
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_connectionStatus.value = ConnectionStatus.connected;
_isConnected.value = true; // 直接设置连接状态
_updateConnectionStatus();
update(); // 立即更新UI
return;
}
// 获取已配对设备
final pairedDevices = await _bluetoothService!.getPairedDevices();
Logger.info('开始获取系统已配对设备列表...');
final pairedDevices = await _bluetoothService!.getPairedDevices()
.timeout(const Duration(seconds: 5), onTimeout: () {
Logger.error('获取已配对设备超时');
return <BluetoothDevice>[];
});
if (pairedDevices.isEmpty) {
Logger.info('没有找到已配对设备');
_connectionStatus.value = ConnectionStatus.disconnected;
update(); // 立即更新UI
return;
}
// 遍历配对设备,查找已连接的设备
for (var device in pairedDevices) {
try {
final state = await device.connectionState.first;
if (state == BluetoothConnectionState.connected) {
// 找到已连接的设备,更新UI
final success = await _bluetoothService!.connectToDevice(device);
if (success) {
Logger.info('使用已连接的已配对设备: ${device.platformName}');
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_connectionStatus.value = ConnectionStatus.connected;
_updateConnectionStatus();
return;
}
}
} catch (e) {
// 忽略单个设备检查错误
Logger.error('检查设备连接状态失败: $e');
}
Logger.info('发现 ${pairedDevices.length} 个已配对设备');
for (var i = 0; i < pairedDevices.length; i++) {
var device = pairedDevices[i];
Logger.info('已配对设备 #$i: ${device.platformName} (${device.remoteId.str})');
}
// 如果没有已连接的设备,尝试连接第一个配对设备
// 遍历配对设备,检查是否有需要连接的设备
Logger.info('开始查找设备进行连接...');
if (pairedDevices.isNotEmpty) {
Logger.info('尝试连接第一个配对设备: ${pairedDevices.first.platformName}');
final success = await _bluetoothService!.connectToDevice(pairedDevices.first);
// 选择第一个配对设备进行连接
var deviceToConnect = pairedDevices.first;
Logger.info('尝试连接配对设备: ${deviceToConnect.platformName ?? "未命名设备"}');
final success = await _bluetoothService!.connectToDevice(deviceToConnect)
.timeout(const Duration(seconds: 5), onTimeout: () {
Logger.error('连接设备 ${deviceToConnect.platformName ?? "未命名设备"} 超时');
return false;
});
if (success) {
Logger.info('自动连接到已配对设备: ${pairedDevices.first.platformName}');
Logger.info('成功连接到设备: ${deviceToConnect.platformName ?? "未命名设备"}');
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_connectionStatus.value = ConnectionStatus.connected;
_isConnected.value = true;
_updateConnectionStatus();
update(); // 立即更新UI
} else {
// 连接失败
Logger.error('连接设备 ${deviceToConnect.platformName ?? "未命名设备"} 失败');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '连接设备失败,请重试';
update(); // 立即更新UI
}
} else {
_connectionStatus.value = ConnectionStatus.disconnected;
update(); // 立即更新UI
}
}
} catch (e) {
Logger.error('检查已配对设备失败: $e');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '检查设备失败: ${e.toString()}';
update(); // 立即更新UI
}
}
@ -369,13 +605,18 @@ class HomeController extends GetxController {
return;
}
// 设置正在刷新状态
// 设置正在刷新状态,但保留当前设备信息显示
_connectionStatus.value = ConnectionStatus.connecting;
update(); // 立即更新UI状态
// 强制检查当前蓝牙连接状态
_checkAndUpdateCurrentConnectionState();
if (_bluetoothService!.selectedDevice != null) {
// 如果有选中的设备,刷新设备信息
_deviceInfo.assignAll(_bluetoothService!.getConnectedDeviceInfo());
_updateConnectionStatus();
update(); // 确保UI更新
// 检查刷新后的连接状态
if (_isConnected.value) {
@ -387,19 +628,22 @@ class HomeController extends GetxController {
colorText: Colors.green[800],
);
} else {
// 设备可能已断开连接
_connectionStatus.value = ConnectionStatus.disconnected;
Get.snackbar(
'提示',
'设备已断开连接',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.amber[100],
colorText: Colors.amber[800],
);
// 尝试重新连接
await _checkPairedDevices();
// 设备可能已断开连接,尝试使用存储的设备信息重新连接
if (_bluetoothService!.lastConnectedDeviceInfo.isNotEmpty) {
_connectionStatus.value = ConnectionStatus.disconnected;
update(); // 更新状态
_reconnectToLastDevice();
} else {
// 上次连接的设备信息也为空,尝试连接已配对设备
await _checkPairedDevices();
}
}
} else if (_bluetoothService!.lastConnectedDeviceInfo.isNotEmpty) {
// 如果没有选中的设备但有上次连接的设备信息,尝试重新连接
_deviceInfo.assignAll(_bluetoothService!.lastConnectedDeviceInfo);
_updateConnectionStatus();
update(); // 确保UI更新
_reconnectToLastDevice();
} else {
// 如果没有选中的设备,尝试连接已配对设备
await _checkPairedDevices();
@ -426,6 +670,7 @@ class HomeController extends GetxController {
Logger.error('刷新设备信息失败: $e');
_connectionStatus.value = ConnectionStatus.failed;
_connectionErrorMsg.value = '刷新设备信息失败: ${e.toString()}';
update(); // 确保状态更新
Get.snackbar(
'提示',

160
lib/modules/pairing/controllers/pairing_controller.dart

@ -49,9 +49,9 @@ class PairingController extends GetxController {
// 启动搜索动画
_startSearchingAnimation();
// 延迟初始化蓝牙服务,避免在应用启动时就请求权限
// 延迟更久初始化蓝牙服务,避免在应用启动时就请求权限和阻塞主线程
// 改为延迟初始化,给UI足够时间渲染
Future.delayed(const Duration(milliseconds: 500), () {
Future.delayed(const Duration(milliseconds: 1500), () {
_initBluetoothService();
});
}
@ -69,6 +69,7 @@ class PairingController extends GetxController {
if (Get.isRegistered<BluetoothService>()) {
_bluetoothService = Get.find<BluetoothService>();
} else {
// 在后台初始化蓝牙服务
_bluetoothService = await Get.put(BluetoothService()).init();
}
@ -82,8 +83,8 @@ class PairingController extends GetxController {
// 如果蓝牙开启,开始扫描设备
if (on) {
// 延迟开始扫描,避免权限请求过早
Future.delayed(const Duration(milliseconds: 300), () {
// 延迟开始扫描,避免权限请求过早和主线程阻塞
Future.delayed(const Duration(milliseconds: 800), () {
_startScanningDevices();
});
} else {
@ -96,8 +97,8 @@ class PairingController extends GetxController {
// 如果蓝牙已经开启,直接开始扫描
if (_bluetoothService.isOn) {
_isBluetoothOn.value = true;
// 延迟开始扫描,避免权限请求过早
Future.delayed(const Duration(milliseconds: 300), () {
// 延迟开始扫描,避免权限请求过早和主线程阻塞
Future.delayed(const Duration(milliseconds: 800), () {
_startScanningDevices();
});
} else {
@ -155,116 +156,66 @@ class PairingController extends GetxController {
// 开始扫描蓝牙设备
Future<void> _startScanningDevices() async {
try {
// 先检查是否已有连接的设备
if (_bluetoothService.connectedDevices.isNotEmpty) {
// 有已连接的设备,直接使用
_deviceFound(_bluetoothService.connectedDevices.first);
_searchStatus.value = SearchStatus.searching;
// 先检查是否有上次连接的设备信息
if (_bluetoothService.lastConnectedDeviceInfo.isNotEmpty &&
_bluetoothService.lastConnectedDeviceInfo['connected'] == true) {
Logger.info('使用上次连接的设备信息');
_deviceInfo.value = _bluetoothService.lastConnectedDeviceInfo;
_onDeviceFound();
return;
}
// 检查是否有已配对的设备
if (await _checkPairedDevices()) {
// 已找到并成功连接到配对设备
// 使用BluetoothService的自动连接功能查找设备
Logger.info('尝试自动连接设备');
BluetoothDevice? device = await _bluetoothService.autoConnectDevice()
.timeout(const Duration(seconds: 8), onTimeout: () {
Logger.info('自动连接设备超时');
return null;
});
if (device != null) {
Logger.info('自动连接设备成功: ${device.platformName}');
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo();
_onDeviceFound();
return;
}
// 搜索新设备
_searchStatus.value = SearchStatus.searching;
await _bluetoothService.startScan(timeout: const Duration(seconds: 10));
// 如果自动连接失败,尝试扫描新设备
Logger.info('自动连接失败,开始扫描新设备');
device = await _bluetoothService.scanAndConnectToDevice(
timeout: const Duration(seconds: 5)
).timeout(const Duration(seconds: 6), onTimeout: () {
Logger.info('扫描并连接设备超时');
return null;
});
// 检查扫描结果
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();
}
if (device != null) {
Logger.info('扫描并连接设备成功: ${device.platformName}');
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo();
_onDeviceFound();
} else {
// 未找到设备
// 未找到任何设备
_errorMessage.value = '未找到蓝牙设备,请确保设备已开启并在附近';
_searchStatus.value = SearchStatus.failed;
_stopSearchingAnimation();
}
} catch (e) {
Logger.error('扫描蓝牙设备失败: $e');
_errorMessage.value = '扫描蓝牙设备失败: ${e.toString()}';
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) {
// 设备找到并连接成功后的处理
void _onDeviceFound() {
_searchStatus.value = SearchStatus.found;
_stopSearchingAnimation();
// 获取设备信息
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo();
// 延迟后跳转到主页,同时传递设备信息
// 更新日志并延迟跳转到主页
Logger.info('设备连接成功,准备跳转到主页');
Timer(const Duration(seconds: 1), () {
Get.offAllNamed(Routes.home, arguments: _deviceInfo.value);
});
@ -272,24 +223,25 @@ class PairingController extends GetxController {
// 手动连接
void manualConnect() {
if (_searchStatus.value == SearchStatus.searching) {
// 如果正在搜索,则停止搜索
_bluetoothService.stopScan();
}
// 停止当前扫描(如果有)
_bluetoothService.stopScan();
// 重新开始搜索
// 更新UI状态
_startSearchingAnimation();
_searchStatus.value = SearchStatus.searching;
_errorMessage.value = '';
// 直接开始扫描并连接
_startScanningDevices();
}
// 稍后再说
void skipConnecting() {
if (_searchStatus.value == SearchStatus.searching) {
// 如果正在搜索,则停止搜索
_bluetoothService.stopScan();
}
// 停止当前扫描
_bluetoothService.stopScan();
_stopSearchingAnimation();
// 直接跳转到主页
Get.offAllNamed(Routes.home);
}
}
Loading…
Cancel
Save