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.

330 lines
9.0 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 {
/// 播放按钮
play,
/// 暂停按钮
pause,
/// 下一曲按钮
next,
/// 上一曲按钮
previous,
/// 快进按钮
seekForward,
/// 快退按钮
seekBackward,
/// 播放/暂停切换按钮
togglePlayPause,
/// 未知按钮
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 'play':
buttonType = MediaButtonType.play;
break;
case 'pause':
buttonType = MediaButtonType.pause;
break;
case 'next':
buttonType = MediaButtonType.next;
break;
case 'previous':
buttonType = MediaButtonType.previous;
break;
case 'seekForward':
buttonType = MediaButtonType.seekForward;
break;
case 'seekBackward':
buttonType = MediaButtonType.seekBackward;
break;
case 'togglePlayPause':
buttonType = MediaButtonType.togglePlayPause;
break;
default:
buttonType = MediaButtonType.unknown;
}
return MediaButtonEvent(
buttonType: buttonType,
timestamp: map['timestamp'] as int? ?? DateTime.now().millisecondsSinceEpoch,
);
}
@override
String toString() {
switch (buttonType) {
case MediaButtonType.play:
return '蓝牙媒体按钮: 播放';
case MediaButtonType.pause:
return '蓝牙媒体按钮: 暂停';
case MediaButtonType.next:
return '蓝牙媒体按钮: 下一曲';
case MediaButtonType.previous:
return '蓝牙媒体按钮: 上一曲';
case MediaButtonType.seekForward:
return '蓝牙媒体按钮: 快进';
case MediaButtonType.seekBackward:
return '蓝牙媒体按钮: 快退';
case MediaButtonType.togglePlayPause:
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 buttonEvent = MediaButtonEvent.fromMap(eventMap);
// 广播事件
_buttonEventController.add(buttonEvent);
Logger.info('成功处理蓝牙媒体按钮事件: $buttonEvent');
} 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();
}
}