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'); } /// 发起经典蓝牙配对(A2DP 出声的前置动作)。**2026-09-11 为车载香薰新增。** /// /// 返回原生层的状态串: /// - Android:`already_bonded` / `bonding_in_progress` / `bonding_started` /// (Android 没有"直接连某个 profile"的公开 API,配对成功后系统自己接 A2DP) /// - iOS:恒为 `unsupported_ios` —— Apple 不提供发起经典蓝牙配对的接口, /// 只能引导用户去「设置 → 蓝牙」手动配一次 /// /// 失败抛 [PlatformException](`INVALID_MAC` / `PERMISSION_DENIED` / /// `BT_DISABLED` / `NO_ADAPTER` / `BOND_FAILED`)。 static Future connectDevice(String macAddress) async { return await _methodChannel.invokeMethod( 'connectDevice', {'macAddress': macAddress}, ); } /// 这台 MAC 当前是不是已经接上音频通路(A2DP)。**2026-09-11 新增。** /// /// Android 查 `BluetoothProfile.A2DP` 的已连接列表; /// iOS 查 `AVAudioSession` 的当前输出(`uid` 去掉后缀就是经典蓝牙 MAC)。 /// 拿不到一律 false,不抛。 static Future isA2dpConnected(String macAddress) async { try { return await _methodChannel.invokeMethod( 'isA2dpConnected', {'macAddress': macAddress}, ) ?? false; } catch (_) { return false; } } /// 监听蓝牙事件(状态变化、设备连接/断开) 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; final bool isActive; BluetoothDevice({ required this.name, required this.address, this.isActive = false, }); factory BluetoothDevice.fromJson(Map json) { return BluetoothDevice( name: json['name'] as String, address: json['address'] as String, isActive: json['isActive'] == 'true', ); } Map toJson() { return { 'name': name, 'address': address, 'isActive': isActive, }; } @override 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 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)'; } } }