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.
308 lines
8.8 KiB
308 lines
8.8 KiB
import 'dart:async';
|
|
import 'dart:io' show Platform;
|
|
import 'package:flutter/services.dart';
|
|
import 'package:get/get.dart';
|
|
import '../../core/utils/logger.dart';
|
|
|
|
/// 蓝牙媒体按钮事件类型
|
|
enum MediaButtonType {
|
|
/// 播放/暂停按钮
|
|
playPause,
|
|
|
|
/// 未知按钮
|
|
unknown
|
|
}
|
|
|
|
/// 蓝牙媒体按钮事件
|
|
class MediaButtonEvent {
|
|
/// 按钮类型
|
|
final MediaButtonType buttonType;
|
|
|
|
/// 事件发生时间戳
|
|
final int timestamp;
|
|
|
|
MediaButtonEvent({
|
|
required this.buttonType,
|
|
required this.timestamp,
|
|
});
|
|
|
|
factory MediaButtonEvent.fromMap(Map<dynamic, dynamic> map) {
|
|
MediaButtonType buttonType;
|
|
|
|
switch (map['buttonType']) {
|
|
case 'playPause':
|
|
buttonType = MediaButtonType.playPause;
|
|
break;
|
|
default:
|
|
// 将所有其他事件类型映射为 playPause
|
|
if (map['buttonType'] == 'play' ||
|
|
map['buttonType'] == 'pause' ||
|
|
map['buttonType'] == 'togglePlayPause') {
|
|
buttonType = MediaButtonType.playPause;
|
|
} else {
|
|
// 忽略其他类型(next, previous, seekForward, seekBackward)
|
|
buttonType = MediaButtonType.unknown;
|
|
}
|
|
}
|
|
|
|
return MediaButtonEvent(
|
|
buttonType: buttonType,
|
|
timestamp: map['timestamp'] as int? ?? DateTime.now().millisecondsSinceEpoch,
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
switch (buttonType) {
|
|
case MediaButtonType.playPause:
|
|
return '蓝牙媒体按钮: 播放/暂停';
|
|
case MediaButtonType.unknown:
|
|
return '蓝牙媒体按钮: 未知';
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 蓝牙媒体按钮服务
|
|
class BluetoothMediaButtonService extends GetxService {
|
|
static BluetoothMediaButtonService get to => Get.find<BluetoothMediaButtonService>();
|
|
|
|
// 方法通道名称
|
|
final MethodChannel _channel = const MethodChannel('com.deep_voice.bluetooth_media_button');
|
|
|
|
// 事件通道名称
|
|
final EventChannel _eventChannel = const EventChannel('com.deep_voice.bluetooth_media_button_events');
|
|
|
|
/// 按钮事件流控制器
|
|
final _buttonEventController = StreamController<MediaButtonEvent>.broadcast();
|
|
|
|
/// 按钮事件流
|
|
Stream<MediaButtonEvent> get buttonEvents => _buttonEventController.stream;
|
|
|
|
/// 是否已启用监听
|
|
final _isListening = false.obs;
|
|
bool get isListening => _isListening.value;
|
|
|
|
/// 是否正在加载
|
|
final isLoading = false.obs;
|
|
|
|
/// 错误信息
|
|
final errorMessage = ''.obs;
|
|
|
|
/// 按钮事件流订阅
|
|
StreamSubscription? _buttonEventSubscription;
|
|
|
|
/// 服务是否已初始化
|
|
bool _isInitialized = false;
|
|
|
|
/// 是否支持媒体按钮服务(iOS 13.0及以上)
|
|
bool get isSupported {
|
|
if (!Platform.isIOS) return true; // 非iOS平台默认支持
|
|
|
|
// 获取平台版本信息
|
|
final String version = Platform.operatingSystemVersion;
|
|
|
|
// 尝试提取iOS版本号 (格式如: "Version 14.5 (Build 18E182)")
|
|
try {
|
|
// 提取版本号
|
|
final RegExp versionRegex = RegExp(r'Version\s+(\d+)\.(\d+)');
|
|
final match = versionRegex.firstMatch(version);
|
|
|
|
if (match != null) {
|
|
final int majorVersion = int.parse(match.group(1) ?? '0');
|
|
return majorVersion >= 13; // iOS 13及以上支持
|
|
}
|
|
} catch (e) {
|
|
Logger.error('解析iOS版本失败: $e');
|
|
}
|
|
|
|
// 无法确定版本时,假设不支持
|
|
return false;
|
|
}
|
|
|
|
/// 初始化服务
|
|
BluetoothMediaButtonService() {
|
|
Logger.info('创建 BluetoothMediaButtonService 实例');
|
|
}
|
|
|
|
/// 初始化媒体按钮服务
|
|
Future<bool> initialize() async {
|
|
if (_isInitialized) {
|
|
Logger.info('BluetoothMediaButtonService 已经初始化');
|
|
return true;
|
|
}
|
|
|
|
// 检查系统版本是否支持
|
|
if (!isSupported) {
|
|
Logger.info('当前iOS版本不支持蓝牙媒体按钮功能(需要iOS 13.0+)');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
Logger.info('正在初始化 BluetoothMediaButtonService...');
|
|
|
|
// 设置事件监听器
|
|
_setupButtonEventListener();
|
|
|
|
_isInitialized = true;
|
|
Logger.info('BluetoothMediaButtonService 初始化成功');
|
|
return true;
|
|
} catch (e) {
|
|
Logger.error('初始化 BluetoothMediaButtonService 失败: $e');
|
|
errorMessage.value = '初始化蓝牙媒体按钮服务失败';
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 设置按钮事件监听器
|
|
void _setupButtonEventListener() {
|
|
_buttonEventSubscription?.cancel();
|
|
|
|
// 设置事件通道监听器
|
|
_buttonEventSubscription = _eventChannel
|
|
.receiveBroadcastStream()
|
|
.listen(_handleButtonEvent, onError: _handleEventStreamError);
|
|
|
|
Logger.info('已设置蓝牙媒体按钮事件监听器');
|
|
}
|
|
|
|
/// 处理按钮事件
|
|
void _handleButtonEvent(dynamic event) {
|
|
Logger.info('BluetoothMediaButtonService 收到原始事件: $event');
|
|
|
|
if (event is! Map) {
|
|
Logger.error('收到无效的蓝牙媒体按钮事件 (非Map类型): $event');
|
|
return;
|
|
}
|
|
|
|
final Map<dynamic, dynamic> eventMap = event;
|
|
Logger.info('蓝牙媒体按钮事件Map: $eventMap');
|
|
|
|
try {
|
|
if (eventMap['type'] == 'mediaButtonEvent') {
|
|
// 获取按钮类型
|
|
final String buttonType = eventMap['buttonType'] as String? ?? 'unknown';
|
|
|
|
// 判断是否为playPause相关事件
|
|
if (buttonType == 'playPause' ||
|
|
buttonType == 'play' ||
|
|
buttonType == 'pause' ||
|
|
buttonType == 'togglePlayPause') {
|
|
|
|
// 创建playPause事件并广播
|
|
final buttonEvent = MediaButtonEvent(
|
|
buttonType: MediaButtonType.playPause,
|
|
timestamp: eventMap['timestamp'] as int? ?? DateTime.now().millisecondsSinceEpoch,
|
|
);
|
|
|
|
|
|
|
|
// 广播事件
|
|
_buttonEventController.add(buttonEvent);
|
|
Logger.info('发送playPause按钮事件: $buttonEvent');
|
|
} else {
|
|
// 忽略其他类型的按钮事件
|
|
Logger.info('忽略非playPause按钮事件: $buttonType');
|
|
}
|
|
} else {
|
|
Logger.warning('收到未知类型的事件: ${eventMap['type']}');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('处理蓝牙媒体按钮事件时出错: $e');
|
|
}
|
|
}
|
|
|
|
/// 处理事件流错误
|
|
void _handleEventStreamError(dynamic error) {
|
|
Logger.error('蓝牙媒体按钮事件流错误: $error');
|
|
errorMessage.value = '蓝牙媒体按钮监听出错';
|
|
}
|
|
|
|
/// 开始监听蓝牙媒体按钮事件
|
|
Future<bool> startButtonListening() async {
|
|
// 检查系统版本是否支持
|
|
if (!isSupported) {
|
|
Logger.info('当前iOS版本不支持蓝牙媒体按钮功能(需要iOS 13.0+)');
|
|
return false;
|
|
}
|
|
|
|
if (!_isInitialized && !(await initialize())) {
|
|
return false;
|
|
}
|
|
|
|
if (_isListening.value) {
|
|
Logger.info('已经在监听蓝牙媒体按钮事件');
|
|
return true;
|
|
}
|
|
|
|
isLoading.value = true;
|
|
|
|
try {
|
|
final result = await _channel.invokeMethod<bool>('startButtonListening') ?? false;
|
|
|
|
if (result) {
|
|
_isListening.value = true;
|
|
Logger.info('开始监听蓝牙媒体按钮事件成功');
|
|
} else {
|
|
errorMessage.value = '开始监听蓝牙媒体按钮事件失败';
|
|
Logger.error('开始监听蓝牙媒体按钮事件失败');
|
|
}
|
|
|
|
isLoading.value = false;
|
|
return result;
|
|
} catch (e) {
|
|
isLoading.value = false;
|
|
errorMessage.value = '开始监听蓝牙媒体按钮事件出错: $e';
|
|
Logger.error('开始监听蓝牙媒体按钮事件出错: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 停止监听蓝牙媒体按钮事件
|
|
Future<bool> stopButtonListening() async {
|
|
if (!_isInitialized) {
|
|
return false;
|
|
}
|
|
|
|
if (!_isListening.value) {
|
|
return true;
|
|
}
|
|
|
|
isLoading.value = true;
|
|
|
|
try {
|
|
final result = await _channel.invokeMethod<bool>('stopButtonListening') ?? false;
|
|
|
|
if (result) {
|
|
_isListening.value = false;
|
|
Logger.info('停止监听蓝牙媒体按钮事件成功');
|
|
} else {
|
|
errorMessage.value = '停止监听蓝牙媒体按钮事件失败';
|
|
Logger.error('停止监听蓝牙媒体按钮事件失败');
|
|
}
|
|
|
|
isLoading.value = false;
|
|
return result;
|
|
} catch (e) {
|
|
isLoading.value = false;
|
|
errorMessage.value = '停止监听蓝牙媒体按钮事件出错: $e';
|
|
Logger.error('停止监听蓝牙媒体按钮事件出错: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 释放资源
|
|
void dispose() {
|
|
_buttonEventSubscription?.cancel();
|
|
_buttonEventSubscription = null;
|
|
_buttonEventController.close();
|
|
_isInitialized = false;
|
|
_isListening.value = false;
|
|
Logger.info('BluetoothMediaButtonService 已释放');
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
dispose();
|
|
super.onClose();
|
|
}
|
|
}
|