diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 9853fa6a0..8c29dfd84 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -124,12 +124,9 @@ dependencies {
// 添加本地插件模块依赖
- implementation(project(":azure_speech"))
- implementation(project(":open_ai_service"))
- implementation(project(":chat_storage")) // 添加新创建的SQLite聊天存储插件
- implementation(project(":jieli")) // 添加新创建的SQLite聊天存储插件
implementation(project(":spotify_sdk"))
implementation(project(":deepvoice_utils"))
+ implementation(project(":ble_service"))
// 添加OkHttp依赖
implementation("com.squareup.okhttp3:okhttp:4.9.3")
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt
index 867a5215d..872981220 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt
@@ -52,7 +52,7 @@ class MainActivity: FlutterActivity() {
FileLogger.init(applicationContext)
// 初始化BLE后台唤醒功能
- initBleBackgroundScan()
+ // initBleBackgroundScan()
FileLogger.d(TAG, "初始化完成")
}
@@ -69,13 +69,9 @@ class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
-
- // 注册经典蓝牙插件
- flutterEngine.plugins.add(ClassicBluetoothPlugin())
}
override fun onDestroy() {
-
super.onDestroy()
}
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
deleted file mode 100644
index 399f6981d..000000000
--- a/android/app/src/profile/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
index 92eb380f8..5f9c97be6 100644
--- a/android/settings.gradle.kts
+++ b/android/settings.gradle.kts
@@ -38,6 +38,7 @@ include(":jieli")
include(":spotify_sdk")
include(":ble_service")
include(":deepvoice_utils")
+include(":classic_bluetooth")
// 设置azure_speech项目的路径
project(":azure_speech").projectDir = file("../local_plugins/azure_speech/android")
project(":open_ai_service").projectDir = file("../local_plugins/open_ai_service/android")
@@ -45,4 +46,5 @@ project(":chat_storage").projectDir = file("../local_plugins/chat_storage/androi
project(":jieli").projectDir = file("../local_plugins/jieli/android")
project(":spotify_sdk").projectDir = file("../local_plugins/spotify_sdk/android")
project(":ble_service").projectDir = file("../local_plugins/ble_service/android")
-project(":deepvoice_utils").projectDir = file("../local_plugins/deepvoice_utils/android")
\ No newline at end of file
+project(":deepvoice_utils").projectDir = file("../local_plugins/deepvoice_utils/android")
+project(":classic_bluetooth").projectDir = file("../local_plugins/classic_bluetooth/android")
\ No newline at end of file
diff --git a/lib/core/bindings/initial_binding.dart b/lib/core/bindings/initial_binding.dart
index a3a096b3a..091f4e5e4 100644
--- a/lib/core/bindings/initial_binding.dart
+++ b/lib/core/bindings/initial_binding.dart
@@ -4,10 +4,7 @@ import '../../data/services/chat_history_service.dart';
import '../../data/services/volcano_translation_service.dart';
import '../../data/services/language_manager.dart';
import '../../data/services/volcano_ai_service.dart';
-import '../../data/services/classic_bluetooth_service.dart';
-import '../../data/services/bluetooth_media_button_service.dart';
import '../../core/utils/logger.dart';
-import '../../data/services/voice_interaction_service.dart';
import '../../data/services/open_ai_service_adapter.dart';
/// 初始绑定,用于管理全局依赖
class InitialBinding extends Bindings {
@@ -39,8 +36,6 @@ class InitialBinding extends Bindings {
// 火山AI服务
Get.lazyPut(() => VolcanoAIService(), fenix: true);
- // 经典蓝牙服务 - 立即初始化以监听蓝牙状态
- Get.lazyPut(() =>ClassicBluetoothService(), fenix: true);
// 蓝牙媒体按钮服务
// Get.lazyPut(
diff --git a/lib/data/services/classic_bluetooth_service.dart b/lib/data/services/classic_bluetooth_service.dart
deleted file mode 100644
index 09319daea..000000000
--- a/lib/data/services/classic_bluetooth_service.dart
+++ /dev/null
@@ -1,243 +0,0 @@
-import 'dart:async';
-import 'package:flutter/services.dart';
-import 'package:get/get.dart';
-import 'package:permission_handler/permission_handler.dart';
-import '../../core/utils/logger.dart';
-import 'dart:io';
-
-/// 蓝牙设备信息
-class BluetoothDevice {
- final String name;
- final String address;
- final String type;
-
- BluetoothDevice({
- required this.name,
- required this.address,
- required this.type
- });
-
- factory BluetoothDevice.fromMap(Map map) {
- return BluetoothDevice(
- name: map['name'] ?? '未知设备',
- address: map['address'] ?? '',
- type: map['type'] ?? 'unknown',
- );
- }
-
- @override
- String toString() => 'BluetoothDevice(name: $name, address: $address, type: $type)';
-}
-
-/// 经典蓝牙服务
-/// 负责经典蓝牙设备的连接状态管理
-class ClassicBluetoothService extends GetxService {
- static ClassicBluetoothService get to => Get.find();
-
- // 通道名称
- final _methodChannel = const MethodChannel('com.yunqiinnovation.classic_bluetooth/methods');
- final _eventChannel = const EventChannel('com.yunqiinnovation.classic_bluetooth/events');
-
- /// 当前连接的设备
- final currentDevice = Rx(null);
-
- /// 已连接耳机设备列表
- final connectedDevices = [].obs;
-
- /// 蓝牙事件监听
- StreamSubscription? _eventSubscription;
-
- /// 蓝牙开关状态
- final bluetoothState = 'unknown'.obs;
-
- /// 蓝牙是否可用
- bool get isBluetoothEnabled => bluetoothState.value == 'on';
-
- /// 服务是否已初始化
- bool _isInitialized = false;
-
- /// 初始化蓝牙服务
- Future initialize() async {
- if (_isInitialized) {
- Logger.info('蓝牙服务已经初始化,跳过');
- return true;
- }
-
- try {
- Logger.info('正在初始化蓝牙服务...');
-
- // 检查蓝牙是否启用
- final bool isEnabled = await _methodChannel.invokeMethod('isBluetoothEnabled') ?? false;
- bluetoothState.value = isEnabled ? 'on' : 'off';
- Logger.info('初始蓝牙状态: ${bluetoothState.value}');
-
- // 设置事件监听
- _setupEventListener();
-
- _isInitialized = true;
- Logger.info('蓝牙服务初始化成功');
-
- // 如果蓝牙已启用,自动获取已连接设备
- if (isEnabled) {
- await refreshConnectedDevices();
- }
-
- return true;
- } catch (e) {
- Logger.error('初始化蓝牙服务失败: $e');
- return false;
- }
- }
-
- /// 设置事件监听
- void _setupEventListener() {
- _eventSubscription?.cancel();
- _eventSubscription = _eventChannel.receiveBroadcastStream().listen((event) {
- if (event is Map) {
- Logger.info('收到蓝牙事件: $event');
-
- // 根据事件类型处理
- final type = event['type'] as String?;
- if (type == 'stateChanged') {
- final state = event['state'] as String?;
- if (state != null) {
- _handleBluetoothStateChange(state);
- }
- } else if (type == 'deviceConnected') {
- final deviceMap = event['device'] as Map?;
- if (deviceMap != null) {
- _handleDeviceConnected(deviceMap);
- }
- } else if (type == 'deviceDisconnected') {
- final deviceMap = event['device'] as Map?;
- if (deviceMap != null) {
- _handleDeviceDisconnected(deviceMap);
- }
- }
- }
- }, onError: (e) {
- Logger.error('蓝牙事件监听错误: $e');
- });
- }
-
-
- /// 刷新已连接的蓝牙设备
- Future refreshConnectedDevices() async {
- // 确保服务已初始化
- if (!_isInitialized && !(await initialize())) {
- return false;
- }
-
- // 如果蓝牙未启用,无法获取设备
- if (!isBluetoothEnabled) {
- Logger.info('蓝牙未启用,无法获取设备');
- return false;
- }
-
- try {
- // 获取已连接的设备
- final devices = await getConnectedDevices();
-
- // 更新设备列表
- connectedDevices.value = devices;
-
- // 如果列表不为空且当前无选定设备,选择第一个
- if (devices.isNotEmpty && currentDevice.value == null) {
- currentDevice.value = devices.first;
- }
-
- return devices.isNotEmpty;
- } catch (e) {
- Logger.error('刷新已连接设备失败: $e');
- return false;
- }
- }
-
- /// 获取已连接的蓝牙设备
- Future> getConnectedDevices() async {
- try {
- // 确保服务已初始化
- if (!_isInitialized && !(await initialize())) {
- return [];
- }
-
- final result = await _methodChannel.invokeMethod('getConnectedDevices');
-
- if (result is List) {
- return result.map((device) => BluetoothDevice.fromMap(device)).toList();
- }
-
- return [];
- } catch (e) {
- Logger.error('获取已连接设备失败: $e');
- return [];
- }
- }
-
- /// 检查蓝牙是否已开启
- Future checkBluetoothEnabled() async {
- try {
- return await _methodChannel.invokeMethod('isBluetoothEnabled') ?? false;
- } catch (e) {
- Logger.error('检查蓝牙状态失败: $e');
- return false;
- }
- }
-
- /// 处理设备连接事件
- void _handleDeviceConnected(Map deviceMap) {
- final device = BluetoothDevice.fromMap(deviceMap);
-
- // 更新设备列表
- if (!connectedDevices.any((d) => d.address == device.address)) {
- connectedDevices.add(device);
- }
-
- // 更新当前设备
- currentDevice.value = device;
-
- Logger.info('设备已连接: ${device.name}');
- }
-
- /// 处理设备断开事件
- void _handleDeviceDisconnected(Map deviceMap) {
- final address = deviceMap['address'] as String?;
-
- if (address != null) {
- // 更新设备列表
- connectedDevices.removeWhere((d) => d.address == address);
-
- // 如果是当前设备,清除当前设备
- if (currentDevice.value?.address == address) {
- currentDevice.value = connectedDevices.isEmpty ? null : connectedDevices.first;
- Logger.info('当前设备已断开连接');
- }
- }
- }
-
- /// 处理蓝牙状态变化
- void _handleBluetoothStateChange(String state) {
- Logger.info('蓝牙状态变化: $state');
-
- // 更新蓝牙状态
- bluetoothState.value = state;
-
- if (state == 'off') {
- // 蓝牙关闭,清空设备信息
- connectedDevices.clear();
- currentDevice.value = null;
- } else if (state == 'on') {
- // 蓝牙重新开启,延迟一小段时间后刷新设备
- Future.delayed(const Duration(milliseconds: 1000), () {
- refreshConnectedDevices();
- });
- }
- }
-
- @override
- void onClose() {
- // 取消事件监听
- _eventSubscription?.cancel();
- super.onClose();
- }
-}
diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart
index db2049bc9..84358806c 100644
--- a/lib/modules/home/controllers/home_controller.dart
+++ b/lib/modules/home/controllers/home_controller.dart
@@ -1,10 +1,10 @@
import 'package:get/get.dart';
import 'dart:async';
import '../../../routes/app_routes.dart';
-import '../../../data/services/classic_bluetooth_service.dart';
import '../../../core/utils/logger.dart';
import 'package:flutter/material.dart';
import '../../explore/controllers/explore_controller.dart';
+import 'package:classic_bluetooth/classic_bluetooth.dart';
// 连接状态枚举
enum ConnectionStatus {
@@ -18,9 +18,6 @@ class HomeController extends GetxController {
static HomeController get to => Get.find();
final ExploreController exploreController = Get.find();
- // 经典蓝牙服务
- final ClassicBluetoothService _bluetoothService = Get.find();
-
// 连接状态
final _connectionStatus = ConnectionStatus.disconnected.obs;
ConnectionStatus get connectionStatus => _connectionStatus.value;
@@ -36,13 +33,18 @@ class HomeController extends GetxController {
final _connectionErrorMsg = ''.obs;
String get connectionErrorMsg => _connectionErrorMsg.value;
- // 从蓝牙服务中直接获取的属性
- Rx get currentDevice => _bluetoothService.currentDevice;
- List get connectedDevices => _bluetoothService.connectedDevices;
- RxString get bluetoothState => _bluetoothService.bluetoothState;
+ // 蓝牙状态和设备信息
+ final _bluetoothState = 'unknown'.obs;
+ String get bluetoothState => _bluetoothState.value;
+
+ final Rx _currentDevice = Rx(null);
+ BluetoothDevice? get currentDevice => _currentDevice.value;
+
+ // 蓝牙事件订阅
+ StreamSubscription? _bluetoothSubscription;
// 蓝牙是否已连接
- bool get isConnected => currentDevice.value != null;
+ bool get isConnected => currentDevice != null;
@override
void onInit() {
@@ -54,22 +56,33 @@ class HomeController extends GetxController {
// 电池模拟更新
_simulateBatteryUpdate();
}
+
+ @override
+ void onClose() {
+ _bluetoothSubscription?.cancel();
+ super.onClose();
+ }
// 初始化蓝牙
Future _initBluetooth() async {
try {
- // 确保蓝牙服务已初始化
- if (!(await _bluetoothService.initialize())) {
- _connectionStatus.value = ConnectionStatus.failed;
- _connectionErrorMsg.value = '初始化蓝牙服务失败';
+ _connectionStatus.value = ConnectionStatus.connecting;
+
+ // 检查蓝牙状态
+ final isEnabled = await ClassicBluetooth.isBluetoothEnabled();
+ _bluetoothState.value = isEnabled ? 'on' : 'off';
+
+ if (!isEnabled) {
+ _connectionStatus.value = ConnectionStatus.disconnected;
+ _connectionErrorMsg.value = '蓝牙未开启';
return;
}
- // 设置监听器
- _setupBluetoothListeners();
+ // 设置蓝牙事件监听
+ _setupBluetoothListener();
- // 更新初始状态
- _updateConnectionStatus();
+ // 获取已连接设备
+ await refreshDeviceConnection();
} catch (e) {
Logger.error('初始化蓝牙失败: $e');
@@ -78,29 +91,54 @@ class HomeController extends GetxController {
}
}
- // 设置蓝牙状态监听
- void _setupBluetoothListeners() {
- // 监听当前设备变化
- ever(currentDevice, (_) {
- _updateConnectionStatus();
- });
-
- // 监听蓝牙状态变化
- ever(bluetoothState, (_) {
- _updateConnectionStatus();
+ // 设置蓝牙事件监听
+ void _setupBluetoothListener() {
+ _bluetoothSubscription?.cancel();
+
+ _bluetoothSubscription = ClassicBluetooth.events.listen((event) {
+ if (event.type == 'stateChanged' && event.state != null) {
+ _bluetoothState.value = event.state!;
+
+ // 如果蓝牙关闭,清空设备信息
+ if (event.state == 'off') {
+ _currentDevice.value = null;
+ _connectionErrorMsg.value = '蓝牙未开启';
+ }
+
+ _updateConnectionStatus();
+ } else if (event.type == 'deviceConnected' && event.device != null) {
+ final newDevice = event.device!;
+
+ // 更新当前设备
+ _currentDevice.value = newDevice;
+ _connectionErrorMsg.value = '';
+ _updateConnectionStatus();
+ } else if (event.type == 'deviceDisconnected' && event.device != null) {
+ final disconnectedDevice = event.device!;
+
+ // 如果断开的是当前设备,清除当前设备
+ if (_currentDevice.value?.address == disconnectedDevice.address) {
+ _currentDevice.value = null;
+ _connectionErrorMsg.value = '设备已断开连接';
+ }
+
+ _updateConnectionStatus();
+ }
+ }, onError: (error) {
+ Logger.error('蓝牙事件流错误: $error');
});
}
// 更新连接状态
void _updateConnectionStatus() {
- if (bluetoothState.value == 'off') {
+ if (bluetoothState == 'off') {
_connectionStatus.value = ConnectionStatus.disconnected;
_deviceBattery.value = null;
update();
return;
}
- if (currentDevice.value != null) {
+ if (currentDevice != null) {
_connectionStatus.value = ConnectionStatus.connected;
} else {
_connectionStatus.value = ConnectionStatus.disconnected;
@@ -116,12 +154,14 @@ class HomeController extends GetxController {
_connectionStatus.value = ConnectionStatus.connecting;
update();
- final success = await _bluetoothService.refreshConnectedDevices();
+ final devices = await ClassicBluetooth.getConnectedDevices();
- if (!success) {
- _connectionErrorMsg.value = '未找到已连接的设备';
- } else {
+ if (devices.isNotEmpty) {
+ _currentDevice.value = devices.first;
_connectionErrorMsg.value = '';
+ } else {
+ _currentDevice.value = null;
+ _connectionErrorMsg.value = '未找到已连接的设备';
}
} catch (e) {
Logger.error('刷新设备连接失败: $e');
@@ -184,7 +224,7 @@ class HomeController extends GetxController {
// 获取连接状态对应的文本
String getConnectionStatusText() {
// 如果蓝牙关闭,优先显示蓝牙状态
- if (bluetoothState.value == 'off') {
+ if (bluetoothState == 'off') {
return 'bluetoothOff'.tr; // 蓝牙已关闭
}
@@ -203,7 +243,7 @@ class HomeController extends GetxController {
// 获取设备名称
String getDeviceName() {
- return currentDevice.value?.name ?? 'unknownEquipment'.tr; // 未知设备
+ return currentDevice?.name ?? 'unknownEquipment'.tr; // 未知设备
}
// 获取信号强度(模拟数据)
@@ -226,6 +266,6 @@ class HomeController extends GetxController {
// 获取设备ID
String getDeviceId() {
- return currentDevice.value?.address ?? 'unknown'.tr; // 未知
+ return currentDevice?.address ?? 'unknown'.tr; // 未知
}
}
diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart
index a8c1798ca..9a79931be 100644
--- a/lib/modules/pairing/controllers/pairing_controller.dart
+++ b/lib/modules/pairing/controllers/pairing_controller.dart
@@ -3,17 +3,14 @@ import 'package:get/get.dart';
import 'dart:async';
import 'package:permission_handler/permission_handler.dart';
import '../../../routes/app_routes.dart';
-import '../../../data/services/classic_bluetooth_service.dart';
import '../../../core/utils/logger.dart';
import 'dart:io';
+import 'package:classic_bluetooth/classic_bluetooth.dart';
-/// 配对控制器,负责显示已连接经典蓝牙设备和处理基本配对流程
+/// 配对控制器,负责检查蓝牙权限、状态,并处理配对流程
class PairingController extends GetxController {
static PairingController get to => Get.find();
- // 经典蓝牙服务
- final ClassicBluetoothService _bluetoothService = Get.find();
-
// 状态标志
final isLoading = false.obs;
@@ -21,20 +18,22 @@ class PairingController extends GetxController {
final _hasPermissions = false.obs;
bool get hasPermissions => _hasPermissions.value;
- // 蓝牙服务是否可用
- final _isBluetoothServiceAvailable = true.obs;
- bool get isBluetoothServiceAvailable => _isBluetoothServiceAvailable.value;
-
+ // 蓝牙状态
+ final _bluetoothState = 'unknown'.obs;
+ String get bluetoothState => _bluetoothState.value;
+
// 状态描述(用于UI显示)
final statusDescription = 'initializing'.tr.obs;
// 是否正在跳转到主页
bool _isNavigatingToHome = false;
- // 当前连接设备和设备列表(直接从服务获取)
- Rx get currentDevice => _bluetoothService.currentDevice;
- RxList get connectedDevices => _bluetoothService.connectedDevices;
- RxString get bluetoothState => _bluetoothService.bluetoothState;
+ // 当前连接设备
+ final Rx _currentDevice = Rx(null);
+ BluetoothDevice? get currentDevice => _currentDevice.value;
+
+ // 蓝牙事件订阅
+ StreamSubscription? _bluetoothSubscription;
@override
void onInit() {
@@ -42,6 +41,12 @@ class PairingController extends GetxController {
_initialize();
}
+ @override
+ void onClose() {
+ _bluetoothSubscription?.cancel();
+ super.onClose();
+ }
+
/// 初始化流程
Future _initialize() async {
try {
@@ -54,31 +59,28 @@ class PairingController extends GetxController {
return;
}
- statusDescription.value = 'initializing'.tr;
+ // 监听蓝牙状态变化
+ _setupBluetoothListener();
+
+ // 检查蓝牙状态
+ statusDescription.value = 'checkingBluetoothStatus'.tr;
+ final isEnabled = await ClassicBluetooth.isBluetoothEnabled();
+ _bluetoothState.value = isEnabled ? 'on' : 'off';
- // 初始化蓝牙服务
- if (!await _bluetoothService.initialize()) {
- Logger.error('蓝牙服务初始化失败');
- statusDescription.value = 'bluetoothInitializationFailure'.tr;
- _isBluetoothServiceAvailable.value = false;
+ if (!isEnabled) {
+ statusDescription.value = 'bluetoothTurnedOff'.tr;
return;
}
- // 设置状态监听
- _setupStatusListeners();
-
// 刷新已连接设备
statusDescription.value = 'searchingDevice'.tr;
await refreshConnectedDevices();
} catch (e) {
Logger.error('初始化配对控制器失败: $e');
statusDescription.value = 'initializationFailure'.tr;
- _isBluetoothServiceAvailable.value = false;
} finally {
isLoading.value = false;
- if (hasPermissions) {
- _updateStatusDescription();
- }
+ _updateStatusDescription();
}
}
@@ -91,11 +93,11 @@ class PairingController extends GetxController {
// Android 12+ (SDK 31+) 需要 SCAN 和 CONNECT
// Android 6+ (SDK 23+) 需要 LOCATION
permissionsToRequest.add(Permission.locationWhenInUse); // 基本定位权限
- // Android 12及以上版本才需要请求蓝牙扫描和连接权限
- if (await _getAndroidSdkVersion() >= 31) {
- permissionsToRequest.add(Permission.bluetoothScan);
- permissionsToRequest.add(Permission.bluetoothConnect);
- }
+ // Android 12及以上版本才需要请求蓝牙扫描和连接权限
+ if (await _getAndroidSdkVersion() >= 31) {
+ permissionsToRequest.add(Permission.bluetoothScan);
+ permissionsToRequest.add(Permission.bluetoothConnect);
+ }
} else if (Platform.isIOS) {
permissionsToRequest.add(Permission.bluetooth);
}
@@ -119,50 +121,71 @@ class PairingController extends GetxController {
if (Platform.isAndroid) {
// 这里需要原生代码支持来获取确切的SDK版本,
// 或者使用 device_info_plus 插件
- // 暂时返回一个较高值以触发新权限请求,如果需要精确控制则需要引入插件
- // 或者,如果你的minSdkVersion >= 31,可以直接请求新权限
- // 假设minSdkVersion < 31,我们需要一种方式判断当前运行设备的SDK版本
- // 为了简化,我们这里先假设需要请求新权限,如果你的目标SDK较低,需要调整
+ // 暂时返回一个较高值以触发新权限请求
return 31; // 假设运行在需要新权限的设备上
}
return 0;
}
- /// 设置状态变化监听
- void _setupStatusListeners() {
- // 监听蓝牙状态变化
- ever(bluetoothState, (_) => _updateStatusDescription());
-
- // 监听当前设备变化
- ever(currentDevice, (device) {
- _updateStatusDescription();
-
- // 当设备连接时自动跳转
- if (device != null) {
- _autoNavigateToHome();
- }
- });
+ /// 设置蓝牙状态监听
+ void _setupBluetoothListener() {
+ _bluetoothSubscription?.cancel();
+
+ try {
+ _bluetoothSubscription = ClassicBluetooth.events.listen(
+ (event) {
+ if (event.type == 'stateChanged' && event.state != null) {
+ _bluetoothState.value = event.state!;
+ _updateStatusDescription();
+
+ // 如果蓝牙关闭,清除设备
+ if (event.state == 'off') {
+ _currentDevice.value = null;
+ }
+ } else if (event.type == 'deviceConnected' && event.device != null) {
+ // 直接从事件中获取设备信息
+ final newDevice = event.device!;
+
+ // 更新当前设备
+ _currentDevice.value = newDevice;
+ _updateStatusDescription();
+
+ // 设备连接时自动跳转到主页
+ _autoNavigateToHome();
+ } else if (event.type == 'deviceDisconnected' && event.device != null) {
+ // 直接从事件中获取设备信息
+ final disconnectedDevice = event.device!;
+
+ // 如果断开的是当前设备,清除当前设备
+ if (_currentDevice.value?.address == disconnectedDevice.address) {
+ _currentDevice.value = null;
+ }
+ _updateStatusDescription();
+ }
+ },
+ onError: (error) {
+ Logger.error('蓝牙事件流错误: $error');
+ },
+ );
+ } catch (e) {
+ Logger.error('设置蓝牙事件监听器失败: $e');
+ }
}
/// 更新状态描述
void _updateStatusDescription() {
- if (!hasPermissions) {
- statusDescription.value = 'permissionDenied'.tr;
- return;
- }
-
- if (bluetoothState.value == 'off') {
- statusDescription.value = 'bluetoothTurnedOff'.tr;
+ if (!hasPermissions) {
+ statusDescription.value = 'permissionDenied'.tr;
return;
}
-
- if (currentDevice.value != null) {
- statusDescription.value = '${'connectedDevice'.tr} ${currentDevice.value!.name}';
+
+ if (bluetoothState == 'off') {
+ statusDescription.value = 'bluetoothTurnedOff'.tr;
return;
}
- if (connectedDevices.isNotEmpty) {
- statusDescription.value = '${'findConnectedDevice'.tr} ${connectedDevices.first.name}';
+ if (currentDevice != null) {
+ statusDescription.value = '${'connectedDevice'.tr} ${currentDevice!.name}';
return;
}
@@ -176,9 +199,7 @@ class PairingController extends GetxController {
/// 刷新已连接设备
Future refreshConnectedDevices() async {
- if (!_isBluetoothServiceAvailable.value) return;
-
- if (!await _checkAndRequestPermissions()) {
+ if (!hasPermissions) {
statusDescription.value = 'permissionDenied'.tr;
return;
}
@@ -187,24 +208,31 @@ class PairingController extends GetxController {
isLoading.value = true;
statusDescription.value = 'searchingDevice'.tr;
- await _bluetoothService.refreshConnectedDevices();
+ // 获取已连接的蓝牙设备
+ final devices = await ClassicBluetooth.getConnectedDevices();
+
+ // 如果有设备则设置为当前设备
+ if (devices.isNotEmpty) {
+ _currentDevice.value = devices.first;
+ _autoNavigateToHome();
+ } else {
+ _currentDevice.value = null;
+ }
} catch (e) {
Logger.error('刷新设备失败: $e');
statusDescription.value = 'failedRefreshDevice'.tr;
} finally {
isLoading.value = false;
- if (hasPermissions) {
- _updateStatusDescription();
- }
+ _updateStatusDescription();
}
}
/// 自动跳转到主页
void _autoNavigateToHome() {
- if (_isNavigatingToHome || currentDevice.value == null) return;
+ if (_isNavigatingToHome || currentDevice == null) return;
_isNavigatingToHome = true;
- Logger.info('已找到连接的设备 ${currentDevice.value?.name},自动跳转到主页');
+ Logger.info('已找到连接的设备 ${currentDevice?.name},自动跳转到主页');
Future.delayed(const Duration(milliseconds: 500), () {
Get.offAllNamed(Routes.home);
@@ -214,24 +242,24 @@ class PairingController extends GetxController {
/// 打开系统蓝牙设置
void openBluetoothSettings() {
try {
- if (!hasPermissions) {
- openAppSettings();
- } else if (Platform.isAndroid && bluetoothState.value == 'off') {
- AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
- } else if (Platform.isIOS) {
- openAppSettings();
- } else {
- AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
- }
+ if (!hasPermissions) {
+ openAppSettings();
+ } else if (Platform.isAndroid && bluetoothState == 'off') {
+ AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
+ } else if (Platform.isIOS) {
+ openAppSettings();
+ } else {
+ AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
+ }
} catch (e) {
Logger.error('打开设置失败: $e');
}
}
- /// 打开应用设置
- Future openAppSettings() async {
- await AppSettings.openAppSettings();
- }
+ /// 打开应用设置
+ Future openAppSettings() async {
+ await AppSettings.openAppSettings();
+ }
/// 跳过连接
void skipConnecting() {
diff --git a/local_plugins/classic_bluetooth/android/build.gradle.kts b/local_plugins/classic_bluetooth/android/build.gradle.kts
new file mode 100644
index 000000000..1e055e488
--- /dev/null
+++ b/local_plugins/classic_bluetooth/android/build.gradle.kts
@@ -0,0 +1,37 @@
+plugins {
+ // Android Library 插件
+ id("com.android.library")
+ // Kotlin Android 插件
+ id("org.jetbrains.kotlin.android")
+ id("com.github.johnrengelman.shadow") version "8.1.1"
+}
+
+android {
+ // 命名空间,对应你插件的包名(需与代码内包名保持一致)
+ namespace = "com.yunqiinnovation.classic_bluetooth"
+
+ // 目标 SDK 版本
+ compileSdk = 33
+
+ defaultConfig {
+ // 最低 SDK 版本
+ minSdk = 21
+ targetSdk = 33
+ }
+
+ // Java 语言级别兼容配置
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+
+ // Kotlin 语言级别
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+
+}
+
+dependencies {
+ add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10")
+}
diff --git a/local_plugins/classic_bluetooth/android/settings.gradle.kts b/local_plugins/classic_bluetooth/android/settings.gradle.kts
new file mode 100644
index 000000000..22e118edf
--- /dev/null
+++ b/local_plugins/classic_bluetooth/android/settings.gradle.kts
@@ -0,0 +1 @@
+rootProject.name = "classic_bluetooth"
diff --git a/local_plugins/classic_bluetooth/android/src/main/AndroidManifest.xml b/local_plugins/classic_bluetooth/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..f95589110
--- /dev/null
+++ b/local_plugins/classic_bluetooth/android/src/main/AndroidManifest.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothHelper.kt b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt
similarity index 95%
rename from android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothHelper.kt
rename to local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt
index e8ba00348..254ca1273 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothHelper.kt
+++ b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt
@@ -1,4 +1,4 @@
-package com.yunqiinnovation.deepsound
+package com.yunqiinnovation.classic_bluetooth
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@@ -79,7 +79,6 @@ class ClassicBluetoothHelper(private val context: Context) {
return bluetoothAdapter.isEnabled
} catch (e: Exception) {
- Log.e(TAG, "检查蓝牙状态失败", e)
return false
}
}
@@ -187,24 +186,6 @@ class ClassicBluetoothHelper(private val context: Context) {
callback.onSuccess(devicesList)
}
- /**
- * 检查是否有蓝牙权限
- */
- fun hasBluetoothPermission(): Boolean {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- ContextCompat.checkSelfPermission(
- context,
- Manifest.permission.BLUETOOTH_CONNECT
- ) == PackageManager.PERMISSION_GRANTED
- } else {
- ContextCompat.checkSelfPermission(
- context,
- Manifest.permission.BLUETOOTH
- ) == PackageManager.PERMISSION_GRANTED
- }
- }
-
-
/**
* 开始监听蓝牙状态变化
* @param callback 蓝牙状态回调接口
@@ -314,7 +295,7 @@ class ClassicBluetoothHelper(private val context: Context) {
try {
context.unregisterReceiver(bluetoothReceiver)
} catch (e: Exception) {
- Log.e(TAG, "注销蓝牙接收器失败", e)
+ // 忽略注销失败异常
}
bluetoothReceiver = null
}
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothPlugin.kt b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt
similarity index 95%
rename from android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothPlugin.kt
rename to local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt
index e4c064b40..c6b632deb 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/ClassicBluetoothPlugin.kt
+++ b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt
@@ -1,4 +1,4 @@
-package com.yunqiinnovation.deepsound
+package com.yunqiinnovation.classic_bluetooth
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@@ -58,9 +58,6 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler {
"isBluetoothEnabled" -> {
result.success(bluetoothHelper.isBluetoothEnabled())
}
- "hasBluetoothPermission" -> {
- result.success(bluetoothHelper.hasBluetoothPermission())
- }
else -> {
result.notImplemented()
}
@@ -151,8 +148,6 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler {
}
override fun onDeviceConnected(device: Map) {
- FileLogger.d(TAG, "设备连接: ${device["name"]} (${device["address"]})")
-
// 发送设备连接事件
val eventMap = mapOf(
"type" to "deviceConnected",
@@ -167,8 +162,6 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler {
}
override fun onDeviceDisconnected(device: Map) {
- FileLogger.d(TAG, "设备断开: ${device["name"]} (${device["address"]})")
-
// 发送设备断开事件
val eventMap = mapOf(
"type" to "deviceDisconnected",
@@ -189,6 +182,10 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler {
*/
private fun sendEvent(event: Map) {
try {
+ if (eventSink == null) {
+ return
+ }
+
eventSink?.success(event)
} catch (e: Exception) {
FileLogger.e(TAG, "事件发送失败", e)
diff --git a/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart b/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart
new file mode 100644
index 000000000..eb66ae5b8
--- /dev/null
+++ b/local_plugins/classic_bluetooth/lib/classic_bluetooth.dart
@@ -0,0 +1,115 @@
+import 'dart:async';
+import 'package:flutter/services.dart';
+
+/// 经典蓝牙插件
+class ClassicBluetooth {
+ static const MethodChannel _methodChannel =
+ MethodChannel('com.yunqiinnovation.classic_bluetooth/methods');
+
+ static const EventChannel _eventChannel =
+ EventChannel('com.yunqiinnovation.classic_bluetooth/events');
+
+ static Stream? _eventStream;
+
+ /// 获取已连接的蓝牙设备
+ static Future> getConnectedDevices() async {
+ final List devices = await _methodChannel.invokeMethod('getConnectedDevices');
+ return devices.map((device) => BluetoothDevice.fromJson(device)).toList();
+ }
+
+ /// 检查蓝牙是否已启用
+ static Future isBluetoothEnabled() async {
+ return await _methodChannel.invokeMethod('isBluetoothEnabled');
+ }
+
+ /// 监听蓝牙事件(状态变化、设备连接/断开)
+ static Stream get events {
+ _eventStream ??= _eventChannel
+ .receiveBroadcastStream()
+ .map((dynamic event) => BluetoothEvent.fromJson(event))
+ .handleError((error) {
+ print('[ClassicBluetooth] 事件流错误: $error');
+ });
+
+ return _eventStream!;
+ }
+}
+
+/// 蓝牙设备模型
+class BluetoothDevice {
+ final String name;
+ final String address;
+
+ BluetoothDevice({
+ required this.name,
+ required this.address,
+ });
+
+ factory BluetoothDevice.fromJson(Map json) {
+ return BluetoothDevice(
+ name: json['name'] as String,
+ address: json['address'] as String,
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'name': name,
+ 'address': address,
+ };
+ }
+
+ @override
+ String toString() => 'BluetoothDevice(name: $name, address: $address)';
+}
+
+/// 简化的蓝牙事件类
+class BluetoothEvent {
+ /// 事件类型:stateChanged, deviceConnected, deviceDisconnected
+ final String type;
+
+ /// 蓝牙状态: on, off, turningOn, turningOff, unknown
+ final String? state;
+
+ /// 相关的蓝牙设备
+ final BluetoothDevice? device;
+
+ /// 事件发生时间
+ final DateTime timestamp;
+
+ BluetoothEvent({
+ required this.type,
+ this.state,
+ this.device,
+ required this.timestamp,
+ });
+
+ factory BluetoothEvent.fromJson(Map json) {
+ final String type = json['type'] as String;
+ final timestamp = DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int);
+
+ // 处理设备相关事件
+ BluetoothDevice? device;
+ if (json.containsKey('device')) {
+ device = BluetoothDevice.fromJson(json['device']);
+ }
+
+ return BluetoothEvent(
+ type: type,
+ state: json['state'] as String?,
+ device: device,
+ timestamp: timestamp,
+ );
+ }
+
+ @override
+ String toString() {
+ if (type == 'stateChanged') {
+ return 'BluetoothEvent(type: $type, state: $state)';
+ } else if (type == 'deviceConnected' || type == 'deviceDisconnected') {
+ return 'BluetoothEvent(type: $type, device: $device)';
+ } else {
+ return 'BluetoothEvent(type: $type)';
+ }
+ }
+}
\ No newline at end of file
diff --git a/local_plugins/classic_bluetooth/pubspec.yaml b/local_plugins/classic_bluetooth/pubspec.yaml
new file mode 100644
index 000000000..eca826603
--- /dev/null
+++ b/local_plugins/classic_bluetooth/pubspec.yaml
@@ -0,0 +1,20 @@
+name: classic_bluetooth
+description: 经典蓝牙设备连接和状态监控插件
+version: 0.0.1
+
+environment:
+ sdk: ">=2.17.0 <3.0.0"
+ flutter: ">=2.5.0"
+
+dependencies:
+ flutter:
+ sdk: flutter
+ deepvoice_utils:
+ path: ../deepvoice_utils
+
+flutter:
+ plugin:
+ platforms:
+ android:
+ package: com.yunqiinnovation.classic_bluetooth
+ pluginClass: ClassicBluetoothPlugin
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index d410fbe5e..ff72848c8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -82,6 +82,8 @@ dependencies:
path: local_plugins/ble_service
deepvoice_utils:
path: local_plugins/deepvoice_utils
+ classic_bluetooth:
+ path: local_plugins/classic_bluetooth
dev_dependencies: