Browse Source

上传经典蓝牙列表返回 正在使用状态确认当前设备

weicu
liwei1dao 1 year ago
parent
commit
b87caaca0e
  1. 62
      lib/data/services/bluetooth_manager.dart
  2. 52
      lib/modules/pairing/controllers/pairing_controller.dart
  3. 57
      local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt
  4. 59
      local_plugins/classic_bluetooth/lib/classic_bluetooth.dart
  5. 6
      macos/Podfile.lock

62
lib/data/services/bluetooth_manager.dart

@ -9,59 +9,58 @@ export 'package:classic_bluetooth/classic_bluetooth.dart' show BluetoothDevice;
/// 蓝牙服务 - 管理经典蓝牙服务
class BluetoothManager extends GetxService {
static BluetoothManager get to => Get.find<BluetoothManager>();
// 蓝牙状态
final _bluetoothState = 'unknown'.obs;
String get bluetoothState => _bluetoothState.value;
RxString get bluetoothStateRx => _bluetoothState;
// 当前经典蓝牙设备
final Rx<BluetoothDevice?> currentDeviceRx = Rx<BluetoothDevice?>(null);
BluetoothDevice? get currentDevice => currentDeviceRx.value;
// 订阅
StreamSubscription<BluetoothEvent>? _bluetoothSubscription;
/// 初始化
@override
void onInit() {
super.onInit();
Logger.info('蓝牙服务初始化');
// 设置蓝牙事件监听
_setupBluetoothListener();
// 主动检查当前已连接的设备和蓝牙状态
Future.delayed(Duration.zero, () async {
Logger.info('检查初始蓝牙连接状态');
// 先检查蓝牙是否开启
await isBluetoothEnabled();
// 然后刷新设备连接
await refreshDeviceConnection();
});
}
/// 释放资源
@override
void onClose() {
_bluetoothSubscription?.cancel();
super.onClose();
}
/// 设置经典蓝牙事件监听
void _setupBluetoothListener() {
_bluetoothSubscription?.cancel();
try {
_bluetoothSubscription = ClassicBluetooth.events.listen(
(event) {
if (event.type == 'stateChanged' && event.state != null) {
_bluetoothState.value = event.state!;
Logger.info('蓝牙状态变更: ${event.state}');
// 如果蓝牙关闭,清除设备
if (event.state == 'off') {
currentDeviceRx.value = null;
@ -69,17 +68,19 @@ class BluetoothManager extends GetxService {
} else if (event.type == 'deviceConnected' && event.device != null) {
// 直接从事件中获取设备信息
final newDevice = event.device!;
// 更新当前设备
currentDeviceRx.value = newDevice;
Logger.info('经典蓝牙设备已连接: ${newDevice.name} (${newDevice.address})');
} else if (event.type == 'deviceDisconnected' && event.device != null) {
} else if (event.type == 'deviceDisconnected' &&
event.device != null) {
// 直接从事件中获取设备信息
final disconnectedDevice = event.device!;
Logger.info('经典蓝牙设备已断开: ${disconnectedDevice.name} (${disconnectedDevice.address})');
Logger.info(
'经典蓝牙设备已断开: ${disconnectedDevice.name} (${disconnectedDevice.address})');
// 如果断开的是当前设备,清除当前设备
if (currentDeviceRx.value?.address == disconnectedDevice.address) {
currentDeviceRx.value = null;
@ -95,34 +96,36 @@ class BluetoothManager extends GetxService {
Logger.error('设置蓝牙事件监听器失败: ${e.toString()}');
}
}
/// 刷新设备连接状态
Future<void> refreshDeviceConnection() async {
try {
// 如果BLE未连接,则检查经典蓝牙连接
final devices = await ClassicBluetooth.getConnectedDevices();
if (devices.isNotEmpty) {
for (var device in devices) {
if (device.isActive) {
// 如果有活动设备,直接使用它
currentDeviceRx.value = device;
Logger.info('已连接经典蓝牙设备: ${device.name} (${device.address})');
return;
}
}
final newDevice = devices.first;
// 更新当前设备
currentDeviceRx.value = newDevice;
Logger.info('已连接经典蓝牙设备: ${newDevice.name} (${newDevice.address})');
return;
}
// 没有任何连接
currentDeviceRx.value = null;
Logger.info('未找到已连接的蓝牙设备');
} catch (e) {
Logger.error('刷新设备连接失败: ${e.toString()}');
}
}
/// 检查蓝牙是否已启用
Future<bool> isBluetoothEnabled() async {
try {
@ -134,5 +137,4 @@ class BluetoothManager extends GetxService {
return false;
}
}
}
}

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

@ -490,9 +490,11 @@ class PairingController extends GetxController {
} else {
final authcode_open = AppConfig.env("APP_AUTHCODE_OPEN") ?? "";
if (authcode_open == "true") {
Logger.i(_tag, '进入手动验证流: ${device.name} (${device.address})');
//验证失败 进入手动授权
_transition(PairingState.manualbinding);
} else {
Logger.i(_tag, '设备不支持: ${device.name} (${device.address})');
_setError(ErrorType.deviceNotMatch,
'pleaseConnectDeepSoundDevice'.tr); //请连接DeepSound设备
}
@ -610,34 +612,42 @@ class PairingController extends GetxController {
Future<int> authbindingDevice(BluetoothDevice device) async {
// 检查设备名称是否包含 DeepSound 或 DeapSound
final deviceName = device.name;
DBProduct? product;
// 检查是否已有BLE绑定的设备
final product = AppConfig.config.products
.firstWhere((d) => d.devicename == device.name);
/// 检查是否已有BLE绑定的设备
if (AppConfig.config.products.isNotEmpty) {
final match = AppConfig.config.products.where(
(d) => d.devicename == device.name,
);
product = match.isNotEmpty ? match.first : null;
}
final names = AppConfig.allproductNames();
// 检查是否已有绑定的设备
print("device.address${device.address}");
var existingDevice = User.instance.devices.firstWhere(
(d) =>
d.devicetype == 1 &&
d.devicename == device.name &&
d.devicemac == device.address,
orElse: () => UserDevice(
id: -1,
uid: '',
devicetype: -1,
devicename: '',
devicemac: '',
license: ''),
);
if (existingDevice.id != -1) {
// 已经绑定
return 9;
if (User.instance.devices.isNotEmpty) {
final existingDevice = User.instance.devices.firstWhere(
(d) =>
d.devicetype == 1 &&
d.devicename == device.name &&
d.devicemac == device.address,
orElse: () => UserDevice(
id: -1,
uid: '',
devicetype: -1,
devicename: '',
devicemac: '',
license: ''),
);
if (existingDevice.id != -1) {
// 已经绑定
return 9;
}
}
if (Platform.isAndroid) {
// 检查是否已有BLE绑定的设备
existingDevice = User.instance.devices.firstWhere(
final existingDevice = User.instance.devices.firstWhere(
(d) =>
d.devicetype == 2 &&
d.devicename == device.name &&
@ -751,7 +761,7 @@ class PairingController extends GetxController {
}
await Future.delayed(Duration(seconds: 1));
}
if (product.devicetype == 2) {
if (product != null && product.devicetype == 2) {
//ble设备 必须要扫描到结果
return 0;
} else {

57
local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothHelper.kt

@ -174,11 +174,16 @@ class ClassicBluetoothHelper(private val context: Context) {
// 获取已连接设备
val connectedDevices = proxy.connectedDevices
// 获取当前活跃设备
val activeDevice = getActiveDevice(proxy, profileId)
// 转换为设备信息列表
val devicesList = connectedDevices.map { device ->
val isActive = activeDevice?.address == device.address
mapOf(
"name" to (device.name ?: "未知设备"),
"address" to device.address
"address" to device.address,
"isActive" to isActive.toString()
)
}
@ -186,6 +191,54 @@ class ClassicBluetoothHelper(private val context: Context) {
callback.onSuccess(devicesList)
}
/**
* 获取当前活跃的蓝牙设备
*/
private fun getActiveDevice(proxy: BluetoothProfile, profileId: Int): BluetoothDevice? {
return try {
when (profileId) {
BluetoothProfile.A2DP -> {
// 使用反射调用 getActiveDevice 方法
val method = proxy.javaClass.getDeclaredMethod("getActiveDevice")
method.isAccessible = true
method.invoke(proxy) as? BluetoothDevice
}
BluetoothProfile.HEADSET -> {
// 对于 HEADSET 配置文件,也尝试获取活跃设备
val method = proxy.javaClass.getDeclaredMethod("getActiveDevice")
method.isAccessible = true
method.invoke(proxy) as? BluetoothDevice
}
else -> null
}
} catch (e: Exception) {
Log.w(TAG, "无法获取活跃设备: ${e.message}")
// 如果无法获取活跃设备,可以尝试其他方法
// 比如检查连接状态或音频焦点
getActiveDeviceFallback(proxy)
}
}
/**
* 获取活跃设备的备用方法
*/
private fun getActiveDeviceFallback(proxy: BluetoothProfile): BluetoothDevice? {
return try {
val connectedDevices = proxy.connectedDevices
// 如果只有一个连接的设备,则认为它是活跃的
if (connectedDevices.size == 1) {
connectedDevices.first()
} else {
// 如果有多个设备,可以通过其他方式判断
// 这里简单返回第一个,实际应用中可能需要更复杂的逻辑
connectedDevices.firstOrNull()
}
} catch (e: Exception) {
Log.w(TAG, "备用方法获取活跃设备失败: ${e.message}")
null
}
}
/**
* 开始监听蓝牙状态变化
* @param callback 蓝牙状态回调接口
@ -361,4 +414,4 @@ class ClassicBluetoothHelper(private val context: Context) {
TURNING_ON,
TURNING_OFF
}
}
}

59
local_plugins/classic_bluetooth/lib/classic_bluetooth.dart

@ -3,34 +3,35 @@ import 'package:flutter/services.dart';
/// 经典蓝牙插件
class ClassicBluetooth {
static const MethodChannel _methodChannel =
static const MethodChannel _methodChannel =
MethodChannel('com.yunqiinnovation.classic_bluetooth/methods');
static const EventChannel _eventChannel =
static const EventChannel _eventChannel =
EventChannel('com.yunqiinnovation.classic_bluetooth/events');
static Stream<BluetoothEvent>? _eventStream;
/// 获取已连接的蓝牙设备
static Future<List<BluetoothDevice>> getConnectedDevices() async {
final List<dynamic> devices = await _methodChannel.invokeMethod('getConnectedDevices');
final List<dynamic> devices =
await _methodChannel.invokeMethod('getConnectedDevices');
return devices.map((device) => BluetoothDevice.fromJson(device)).toList();
}
/// 检查蓝牙是否已启用
static Future<bool> isBluetoothEnabled() async {
return await _methodChannel.invokeMethod('isBluetoothEnabled');
}
/// 监听蓝牙事件(状态变化、设备连接/断开)
static Stream<BluetoothEvent> get events {
_eventStream ??= _eventChannel
.receiveBroadcastStream()
.map((dynamic event) => BluetoothEvent.fromJson(event))
.handleError((error) {
print('[ClassicBluetooth] 事件流错误: $error');
});
print('[ClassicBluetooth] 事件流错误: $error');
});
return _eventStream!;
}
}
@ -39,61 +40,67 @@ class ClassicBluetooth {
class BluetoothDevice {
final String name;
final String address;
final bool isActive;
BluetoothDevice({
required this.name,
required this.address,
this.isActive = false,
});
factory BluetoothDevice.fromJson(Map<dynamic, dynamic> json) {
return BluetoothDevice(
name: json['name'] as String,
address: json['address'] as String,
isActive: json['isActive'] == 'true',
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'address': address,
'isActive': isActive,
};
}
@override
String toString() => 'BluetoothDevice(name: $name, address: $address)';
String toString() =>
'BluetoothDevice(name: $name, address: $address, isActive: $isActive)';
}
/// 简化的蓝牙事件类
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<dynamic, dynamic> json) {
final String type = json['type'] as String;
final timestamp = DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int);
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?,
@ -101,7 +108,7 @@ class BluetoothEvent {
timestamp: timestamp,
);
}
@override
String toString() {
if (type == 'stateChanged') {
@ -112,4 +119,4 @@ class BluetoothEvent {
return 'BluetoothEvent(type: $type)';
}
}
}
}

6
macos/Podfile.lock

@ -14,6 +14,8 @@ PODS:
- FlutterMacOS (1.0.0)
- record_darwin (1.0.0):
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- FlutterMacOS
- window_size (0.0.2):
- FlutterMacOS
@ -26,6 +28,7 @@ DEPENDENCIES:
- flutter_tts (from `Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- record_darwin (from `Flutter/ephemeral/.symlinks/plugins/record_darwin/macos`)
- sign_in_with_apple (from `Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos`)
- window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`)
EXTERNAL SOURCES:
@ -45,6 +48,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
record_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/record_darwin/macos
sign_in_with_apple:
:path: Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos
window_size:
:path: Flutter/ephemeral/.symlinks/plugins/window_size/macos
@ -57,6 +62,7 @@ SPEC CHECKSUMS:
flutter_tts: ae915565cc6948444b513acc8ee021993281e027
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
record_darwin: 30509266ae213af8afdb09a8ae7467cb64c1377e
sign_in_with_apple: 6673c03c9e3643f6c8d33601943fbfa9ae99f94e
window_size: 4bd15034e6e3d0720fd77928a7c42e5492cfece9
PODFILE CHECKSUM: 8c4442624fc136b0afb378a2502958e01c05d073

Loading…
Cancel
Save