using UnityEngine; using System; using System.Collections.Generic; using Kill.Core; using Kill.UI; using Kill.UI.Components; using static BluetoothLEHardwareInterface; namespace Kill.Bluetooth { /// /// 蓝牙设备信息 /// [Serializable] public class BluetoothDevice { public string Address; // 设备地址(Android为MAC,iOS为UUID) public string Name; // 设备名称 public int Rssi; // 信号强度 public byte[] info; // 广播/制造商数据 public string MacFromBroadcast; // 从广播数据解析出的真实MAC地址(iOS端使用) public BluetoothDevice(string address, string name, int rssi=0,byte[] bytes=null) { Address = address; Name = name; Rssi = rssi; info=bytes; MacFromBroadcast = ParseMacFromBytes(bytes); } /// /// 从广播数据中解析真实MAC地址 /// 广播数据格式: [2字节头部] + [6字节MAC地址] /// public static string ParseMacFromBytes(byte[] bytes) { if (bytes == null || bytes.Length < 8) return null; // MAC地址位于 bytes[2]~bytes[7](共6字节) return string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]); } /// /// 获取用于匹配和显示的有效地址 /// iOS: 优先使用广播中的MAC,否则使用UUID /// Android: Address本身就是MAC,直接使用 /// public string GetEffectiveAddress() { return MacFromBroadcast ?? Address; } } /// /// 蓝牙管理器 - 提供基础的蓝牙扫描、连接、断开功能 /// public class BluetoothManager : MonoBehaviour { public static BluetoothManager Instance { get; private set; } // 事件定义 public event Action OnInitialized; // 初始化完成事件 public event Action OnDeviceFound; // 发现设备事件 public event Action OnConnected; // 连接成功事件 (参数: 设备地址) public event Action OnConnectFailed; // 连接失败事件 (参数: 设备地址) public event Action OnDisconnected; // 断开连接事件 (参数: 设备地址) public event Action OnError; // 错误事件 public event Action OnLog; // 日志事件 public event Action OnConnectedSuccess; // 连接成功并可通信事件 (无参数,用于通知BLECommunicationManager) public event Action OnStopScan; public event Action OnStartScan; // 状态 public bool IsInitialized { get; private set; } public bool IsScanning { get; private set; } public bool IsConnected { get; private set; } public string ConnectedDeviceAddress { get; private set; } public string ConnectedDeviceMacAddress { get; private set; } // iOS端连接后存储的真实MAC地址 private string aimMac = ""; // 扫描到的设备列表 public List DiscoveredDevices { get; private set; } = new List(); // 是否自动连接 public bool AutoConnect = true; // 连接超时设置 public float ConnectionTimeout = 10f; // 连接超时时间(秒) private float _connectionTimer; private bool _isConnecting; private string _connectingAddress; // 蓝牙启用提示相关 private Coroutine _enableBtCoroutine; // 等待蓝牙启用的协程 private bool _userDeniedBluetooth = false; // 用户已拒绝过蓝牙开启请求 private bool _pendingStartScan = false; // 是否有待执行的扫描 private float _pendingScanTimeout; // 待执行扫描的超时时间 private string _pendingConnectAddress; // 初始化后待连接的设备地址 private bool _wasBtOn = false; // 上一帧蓝牙是否开启(用于检测状态变化) private Coroutine _stateMonitorCoroutine; // 蓝牙状态监控协程 private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); _stateMonitorCoroutine = StartCoroutine(MonitorBluetoothState()); OnDisconnected += OnSelfDisconnected; } else { Destroy(gameObject); } } private void OnDestroy() { if (Instance == this) { OnDisconnected -= OnSelfDisconnected; if (_stateMonitorCoroutine != null) { StopCoroutine(_stateMonitorCoroutine); _stateMonitorCoroutine = null; } Instance = null; } } public bool needBackHome=true; /// /// 蓝牙断开后延迟跳回主页 /// private void OnSelfDisconnected(string address) { IsConnected=false; // 延迟一下确保主页能读到最新的 IsConnected 状态 if(needBackHome) StartCoroutine(DelayedGoHome()); needBackHome=true; } private System.Collections.IEnumerator DelayedGoHome() { yield return new WaitForSeconds(1f); UIManager.Instance?.OpenMainPage(UIManager.PageName.homePage); } void Start() { Initialize(); } private void Update() { // 检查连接超时 if (_isConnecting) { _connectionTimer -= Time.deltaTime; if (_connectionTimer <= 0) { // 连接超时 _isConnecting = false; Log($"连接超时: {_connectingAddress}"); OnConnectFailed?.Invoke(_connectingAddress); OnError?.Invoke($"连接超时: 无法连接到设备 {_connectingAddress}"); _connectingAddress = null; } } } /// /// 初始化蓝牙(带自动启用) /// public void Initialize() { if (IsInitialized) { Log("蓝牙已经初始化"); OnInitialized?.Invoke(true); return; } // 如果已经在等待蓝牙启用,跳过(不取消旧请求,避免重复弹窗) if (_enableBtCoroutine != null) { Log("已在等待用户启用蓝牙,跳过重复请求"); return; } // 用户已拒绝过蓝牙请求,不再自动弹出提示 if (_userDeniedBluetooth) { Log("用户已拒绝蓝牙开启,跳过初始化"); return; } Log("正在初始化蓝牙..."); // 先检查蓝牙是否开启,如果没有则尝试启用 CheckAndEnableBluetooth(() => { // 蓝牙已启用,执行初始化 DoInitialize(); }); } /// /// 强制初始化蓝牙(清除用户拒绝标记,用于用户主动触发) /// public void ForceInitialize() { _userDeniedBluetooth = false; Initialize(); } /// /// 检查并启用蓝牙 /// private void CheckAndEnableBluetooth(System.Action onBluetoothReady) { #if UNITY_ANDROID && !UNITY_EDITOR using (AndroidJavaClass bluetoothAdapterClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter")) { AndroidJavaObject bluetoothAdapter = bluetoothAdapterClass.CallStatic("getDefaultAdapter"); if (bluetoothAdapter == null) { _enableBtCoroutine = null; OnError?.Invoke("设备不支持蓝牙"); OnInitialized?.Invoke(false); return; } bool isEnabled = bluetoothAdapter.Call("isEnabled"); if (!isEnabled) { Log("蓝牙未开启,使用 Intent 请求用户启用..."); using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) using (AndroidJavaObject currentActivity = unityPlayer.GetStatic("currentActivity")) { AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.bluetooth.adapter.action.REQUEST_ENABLE"); currentActivity.Call("startActivityForResult", intent, 1); } _enableBtCoroutine = StartCoroutine(WaitForBluetoothEnabled(onBluetoothReady)); } else { Log("蓝牙已开启"); onBluetoothReady?.Invoke(); } } #elif UNITY_IOS && !UNITY_EDITOR // iOS 检查蓝牙状态 CheckBluetoothStateIOS(onBluetoothReady); #else // 其他平台直接执行初始化 onBluetoothReady?.Invoke(); #endif } #if UNITY_ANDROID && !UNITY_EDITOR /// /// 轮询等待蓝牙启用(Intent 之后,最长10秒) /// private System.Collections.IEnumerator WaitForBluetoothEnabled(System.Action onBluetoothReady) { float maxTimeout = 10f; float timer = 0f; int checkCount = 0; bool wasUnfocused = false; while (timer < maxTimeout) { checkCount++; using (AndroidJavaClass btClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter")) { AndroidJavaObject adapter = btClass.CallStatic("getDefaultAdapter"); if (adapter != null) { bool btOn = adapter.Call("isEnabled"); if (checkCount <= 4 || checkCount % 10 == 0) Log($"第{checkCount}次: isEnabled={btOn}, 已等待{timer:F1}s"); if (btOn) { Log("蓝牙已成功启用"); _enableBtCoroutine = null; _userDeniedBluetooth = false; onBluetoothReady?.Invoke(); yield break; } } } // 检测用户是否关闭了系统对话框:对话框弹出时 App 失去焦点,关闭后恢复 if (!Application.isFocused) { wasUnfocused = true; } else if (wasUnfocused && timer > 0.5f) { // 焦点恢复但蓝牙仍未开启 → 用户拒绝了 / 关闭了对话框 Log("检测到用户关闭了蓝牙请求对话框,停止等待"); break; } yield return new WaitForSeconds(0.2f); timer += 0.2f; } Log($"等待蓝牙启用结束 (共检查{checkCount}次,已等待{timer:F1}s)"); _enableBtCoroutine = null; _userDeniedBluetooth = true; _pendingStartScan = false; _pendingConnectAddress = null; OnError?.Invoke("蓝牙未开启"); OnInitialized?.Invoke(false); } #endif #if UNITY_IOS && !UNITY_EDITOR [System.Runtime.InteropServices.DllImport("__Internal")] private static extern int GetBluetoothStateIOS(); [System.Runtime.InteropServices.DllImport("__Internal")] private static extern void OpenBluetoothSettingsIOS(); /// /// iOS 检查蓝牙状态 /// 0 = Unknown, 1 = Resetting, 2 = Unsupported, 3 = Unauthorized, 4 = PoweredOff, 5 = PoweredOn /// private void CheckBluetoothStateIOS(System.Action onBluetoothReady) { int state = GetBluetoothStateIOS(); Log($"iOS 蓝牙状态: {state}"); // 5 = PoweredOn (蓝牙已开启) if (state == 5) { Log("iOS 蓝牙已开启"); onBluetoothReady?.Invoke(); } // 4 = PoweredOff (蓝牙关闭) — iOS 系统会自动弹出蓝牙开启对话框,无需手动跳转设置 else if (state == 4) { Log("iOS 蓝牙未开启,等待系统弹出蓝牙开启提示..."); // 不调用 ShowIOSTurnOnBluetoothPrompt(),让 iOS 原生弹窗处理 // 等待蓝牙状态变化(检测焦点变化 + 轮询蓝牙状态) _enableBtCoroutine = StartCoroutine(WaitForIOSBluetoothEnabled(onBluetoothReady)); } // 3 = Unauthorized (未授权) — 需要跳转到应用设置页面让用户开启蓝牙权限 else if (state == 3) { Log("iOS 蓝牙未授权,跳转到应用设置页..."); ShowIOSTurnOnBluetoothPrompt(); _enableBtCoroutine = StartCoroutine(WaitForIOSBluetoothEnabled(onBluetoothReady)); } // 2 = Unsupported (不支持蓝牙) else if (state == 2) { Log("设备不支持蓝牙"); _enableBtCoroutine = null; OnError?.Invoke("设备不支持蓝牙"); OnInitialized?.Invoke(false); } // 其他状态 else { Log($"iOS 蓝牙状态未知: {state},尝试继续初始化"); onBluetoothReady?.Invoke(); } } /// /// iOS: 等待用户从设置返回并开启蓝牙(检测焦点 + 轮询) /// private System.Collections.IEnumerator WaitForIOSBluetoothEnabled(System.Action onBluetoothReady) { float maxTimeout = 15f; float timer = 0f; int checkCount = 0; bool wasUnfocused = false; while (timer < maxTimeout) { checkCount++; int state = GetBluetoothStateIOS(); if (checkCount <= 4 || checkCount % 10 == 0) Log($"iOS 第{checkCount}次: state={state}, 已等待{timer:F1}s"); // 5 = PoweredOn if (state == 5) { Log("iOS 蓝牙已开启"); _enableBtCoroutine = null; _userDeniedBluetooth = false; onBluetoothReady?.Invoke(); yield break; } // 检测用户从设置返回 if (!Application.isFocused) { wasUnfocused = true; } else if (wasUnfocused && timer > 1f) { // 从系统设置返回但蓝牙仍未开启 → 用户未操作 Log("iOS: 从设置返回,蓝牙未开启,停止等待"); break; } yield return new WaitForSeconds(0.3f); timer += 0.3f; } Log($"iOS 等待蓝牙启用结束 (共检查{checkCount}次,已等待{timer:F1}s)"); _enableBtCoroutine = null; _userDeniedBluetooth = true; _pendingStartScan = false; _pendingConnectAddress = null; OnError?.Invoke("请在系统设置中开启蓝牙"); OnInitialized?.Invoke(false); } /// /// 显示 iOS 开启蓝牙提示 /// private void ShowIOSTurnOnBluetoothPrompt() { OpenBluetoothSettingsIOS(); } #endif /// /// 监控蓝牙开关状态变化(App运行时) /// private System.Collections.IEnumerator MonitorBluetoothState() { yield return new WaitForSeconds(2f); // 初始延迟 while (true) { yield return new WaitForSeconds(2f); bool btOn = CheckIfBluetoothIsOn(); if (!_wasBtOn && btOn) { if (!IsInitialized && !_userDeniedBluetooth) { Log("检测到蓝牙已开启,自动初始化..."); Initialize(); } } else if (_wasBtOn && !btOn) { Log("检测到蓝牙已关闭,清理状态..."); if (_enableBtCoroutine != null) { StopCoroutine(_enableBtCoroutine); _enableBtCoroutine = null; } if (IsConnected) { Disconnect(); } if (IsScanning) { StopScan(); } IsInitialized = false; _isFullyInitialized = false; _pendingStartScan = false; _pendingConnectAddress = null; OnInitialized?.Invoke(false); } _wasBtOn = btOn; } } /// /// 跨平台检查蓝牙是否开启 /// private bool CheckIfBluetoothIsOn() { #if UNITY_ANDROID && !UNITY_EDITOR try { using (AndroidJavaClass btClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter")) { AndroidJavaObject adapter = btClass.CallStatic("getDefaultAdapter"); if (adapter != null) return adapter.Call("isEnabled"); } } catch (System.Exception ex) { Log($"检查蓝牙状态异常: {ex.Message}"); } return false; #elif UNITY_IOS && !UNITY_EDITOR return GetBluetoothStateIOS() == 5; #else return true; #endif } /// /// 执行蓝牙初始化 /// // 标记是否已完成初始化 private bool _isFullyInitialized = false; private void DoInitialize() { _isFullyInitialized = false; BluetoothLEHardwareInterface.Initialize(true, false, () => { IsInitialized = true; _isFullyInitialized = true; _enableBtCoroutine = null; _userDeniedBluetooth = false; Log("蓝牙初始化成功"); OnInitialized?.Invoke(true); // 如果有待执行的扫描任务,立即执行 if (_pendingStartScan) { _pendingStartScan = false; Log($"执行待处理的扫描,超时: {_pendingScanTimeout}秒"); DoStartScan(_pendingScanTimeout); } // 如果有待连接的设备地址,连接 if (!string.IsNullOrEmpty(_pendingConnectAddress)) { var addr = _pendingConnectAddress; _pendingConnectAddress = null; Log($"执行待处理的连接: {addr}"); StartCoroutine(DelayedConnectAfterInit(addr)); } }, (error) => { // 忽略 "Service not found" 错误,这是插件内部问题,不影响功能 if (error.Contains("Service not found")) { Log($"蓝牙初始化警告: {error}"); Log("继续初始化..."); IsInitialized = true; _isFullyInitialized = true; _enableBtCoroutine = null; _userDeniedBluetooth = false; OnInitialized?.Invoke(true); // 如果有待执行的扫描任务,立即执行 if (_pendingStartScan) { _pendingStartScan = false; Log($"执行待处理的扫描,超时: {_pendingScanTimeout}秒"); DoStartScan(_pendingScanTimeout); } // 如果有待连接的设备地址,连接 if (!string.IsNullOrEmpty(_pendingConnectAddress)) { var addr = _pendingConnectAddress; _pendingConnectAddress = null; Log($"执行待处理的连接: {addr}"); StartCoroutine(DelayedConnectAfterInit(addr)); } } // 如果已经初始化完成,这是运行时错误,不是初始化错误 else if (_isFullyInitialized) { Log($"蓝牙运行时错误: {error}"); OnError?.Invoke(error); } else { Log($"蓝牙初始化失败: {error}"); _enableBtCoroutine = null; OnError?.Invoke($"初始化失败: {error}"); OnInitialized?.Invoke(false); } }, needLocation: true ); } // /// // /// 延迟尝试自动连接(用于初始化后) // /// // private void TryAutoConnectDelayed() // { // // 如果用户已经开始扫描或连接,跳过自动连接 // if (IsScanning || IsConnected || _isConnecting) // { // Log("用户正在进行扫描或连接,跳过自动连接"); // return; // } // TryAutoConnect(); // } // /// // /// 尝试自动连接上一次连接的设备 // /// // private void TryAutoConnect() // { // string lastAddress = PlayerPrefs.GetString(LAST_DEVICE_ADDRESS_KEY, ""); // string lastName = PlayerPrefs.GetString(LAST_DEVICE_NAME_KEY, ""); // if (string.IsNullOrEmpty(lastAddress)) // { // Log("没有上一次连接的设备记录"); // return; // } // Log($"尝试自动连接上一次设备: {lastName} [{lastAddress}]"); // // 先扫描设备,找到后再连接 // StartScanForAutoConnect(lastAddress); // } // 用于自动连接的临时地址存储 private string _pendingAutoConnectAddress; /// /// 延迟自动连接(确保扫描完全停止后再连接) /// private void DelayedAutoConnect() { if (!string.IsNullOrEmpty(_pendingAutoConnectAddress)) { Log($"[BLE-DEBUG] 自动连接: 延迟连接 {_pendingAutoConnectAddress}"); Connect(_pendingAutoConnectAddress); _pendingAutoConnectAddress = null; } } /// /// 初始化完成后延迟连接设备 /// private System.Collections.IEnumerator DelayedConnectAfterInit(string address) { yield return new WaitForSeconds(0.5f); Connect(address); } /// /// 开始扫描蓝牙设备 /// /// 扫描超时时间(秒),默认10秒 public void StartScan(float timeout = 999f) { if (!IsInitialized) { Log("蓝牙未初始化,自动触发初始化流程..."); _pendingStartScan = true; _pendingScanTimeout = timeout; Initialize(); return; } DoStartScan(timeout); } /// /// 实际执行扫描逻辑 /// private void DoStartScan(float timeout) { if (IsScanning) { Log("已经在扫描中,先停止当前扫描..."); StopScan(); } // 如果还在连接状态,先断开 if (IsConnected) { Log("警告: 扫描时仍处于连接状态,先断开连接..."); Disconnect(); // 延迟一点再开始扫描 Invoke(nameof(DelayedStartScan), 1f); return; } // 清空之前的设备列表 DiscoveredDevices.Clear(); IsScanning = true; Log($"开始扫描蓝牙设备 (超时: {timeout}秒)..."); OnStartScan?.Invoke(); // 开始扫描 BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,null, // 回调2:包含RSSI和制造商数据 (address, name, rssi, bytes) => { AddOrUpdateDevice(address, name, rssi,bytes); }, false // 接收完整的广播/制造商数据 ); // 设置超时自动停止 Invoke(nameof(StopScan), timeout); } /// /// 延迟开始扫描(用于断开连接后) /// private void DelayedStartScan() { Log("延迟扫描开始..."); // 清空设备列表 DiscoveredDevices.Clear(); IsScanning = true; BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,null, (address, name, rssi, bytes) => { AddOrUpdateDevice(address, name, rssi,bytes); }, false ); Invoke(nameof(StopScan), 10f); } /// /// 停止扫描 /// public void StopScan() { if (!IsScanning) return; IsScanning = false; OnStopScan?.Invoke(); // 取消所有扫描相关的Invoke CancelInvoke(nameof(StopScan)); CancelInvoke(nameof(DelayedStartScan)); BluetoothLEHardwareInterface.StopScan(); Log("停止扫描蓝牙设备"); } /// /// 连接指定设备 /// /// 设备地址 public void Connect(string deviceAddress) { if (!IsInitialized) { Log("蓝牙未初始化,自动触发初始化流程..."); _pendingStartScan = true; _pendingScanTimeout = 999f; _pendingConnectAddress = deviceAddress; Initialize(); return; } if (IsConnected) { OnError?.Invoke("已连接到设备,请先断开连接"); return; } // 如果正在连接其他设备,先取消 if (_isConnecting) { Log($"取消之前的连接尝试: {_connectingAddress}"); _isConnecting = false; } Log($"正在连接设备: {deviceAddress}"); // 启动连接超时计时 _isConnecting = true; // 统一使用大写格式保存地址 _connectingAddress = deviceAddress.ToUpper(); _connectionTimer = ConnectionTimeout; BluetoothLEHardwareInterface.ConnectToPeripheral(deviceAddress, // 连接成功回调 (address) => { Log($"设备连接成功: {address}"); }, // 服务发现回调 (address, serviceUUID) => { Log($"[BLE-DEBUG] 发现服务: {serviceUUID}"); }, // 特征发现回调 (address, serviceUUID, characteristicUUID) => { Log($"[BLE-DEBUG] 发现特征: Service={serviceUUID}, Char={characteristicUUID}"); // 首次发现特征时设置连接状态 if (!IsConnected) { // 连接成功,停止超时计时 _isConnecting = false; _connectingAddress = null; IsConnected = true; // 统一使用大写格式保存地址,确保与断开时使用的格式一致 ConnectedDeviceAddress = address.ToUpper(); // 保存连接的设备信息 var device = DiscoveredDevices.Find(d => d.Address.ToUpper() == address.ToUpper()); string deviceName = device != null ? device.Name : "Unknown"; ConnectedDeviceMacAddress = device?.GetEffectiveAddress()?.ToUpper(); //SaveLastConnectedDevice(address, deviceName); OnConnected?.Invoke(address); // 请求高吞吐量:MTU 512 + 高优先级连接间隔 BluetoothLEHardwareInterface.RequestMtu(address, 512, (addr, mtu) => { Log($"MTU 协商完成: {mtu} 字节"); }); BluetoothLEHardwareInterface.BluetoothConnectionPriority(ConnectionPriority.High); Log("已请求高优先级 BLE 连接"); // 延迟通知连接成功并可通信 Invoke(nameof(NotifyConnectedSuccess), 0.5f); } }, // 断开连接回调 (disconnectAddress) => { // 如果正在连接中就被断开,说明连接失败 if (_isConnecting && disconnectAddress.ToUpper() == _connectingAddress?.ToUpper()) { _isConnecting = false; Log($"连接失败: {disconnectAddress}"); OnConnectFailed?.Invoke(disconnectAddress); _connectingAddress = null; } // 设备断开连接(使用不区分大小写的地址比较) else if (IsConnected && disconnectAddress.ToUpper() == ConnectedDeviceAddress?.ToUpper()) { IsConnected = false; string disconnectedAddr = ConnectedDeviceAddress; ConnectedDeviceAddress = null; ConnectedDeviceMacAddress = null; Log($"设备断开连接: {disconnectAddress}"); OnDisconnected?.Invoke(disconnectAddress); // 执行清理 CleanupAfterDisconnect(); } else { Log($"收到未处理的断开回调: {disconnectAddress}, 当前连接状态: IsConnected={IsConnected}"); } } ); } /// /// 按名称连接设备 /// /// 设备名称 public void ConnectByName(string deviceName) { var device = DiscoveredDevices.Find(d => d.Name == deviceName); if (device != null) { Connect(device.Address); } else { OnError?.Invoke($"未找到设备: {deviceName}"); } } /// /// 断开当前连接(带协议通知) /// 先发送0x70断开命令给设备,再断开BLE连接 /// public void Disconnect(bool backHome=false) { needBackHome=backHome; if (!IsConnected) { Log("当前没有连接的设备"); return; } string addressToDisconnect = ConnectedDeviceAddress; Log($"正在断开连接: {addressToDisconnect}"); // 先停止扫描,避免扫描干扰断开过程 if (IsScanning) { StopScan(); } // 取消可能正在进行的连接尝试 if (_isConnecting) { _isConnecting = false; _connectingAddress = null; } // 先通过BLE协议发送断开命令(0x70) Log($"检查BLECommunicationManager: Instance={(BLECommunicationManager.Instance != null ? "存在" : "null")}"); if (BLECommunicationManager.Instance != null) { Log("发送断开命令(0x70)到设备..."); BLECommunicationManager.Instance.Disconnect((success) => { Log($"断开命令发送结果: {(success ? "成功" : "失败")}"); // 无论命令是否成功,都执行BLE断开 PerformBLEDisconnect(addressToDisconnect); }); } else { Log("BLECommunicationManager.Instance 为 null,跳过0x70命令,直接断开BLE"); // 如果没有BLE通信管理器,直接断开BLE PerformBLEDisconnect(addressToDisconnect); } } /// /// 执行BLE层断开连接 /// private void PerformBLEDisconnect(string addressToDisconnect) { Log($"执行BLE断开: {addressToDisconnect}"); BluetoothLEHardwareInterface.DisconnectPeripheral(addressToDisconnect, (address) => { Log($"BLE断开连接回调: {address}"); } ); // 立即清理状态 IsConnected = false; ConnectedDeviceAddress = null; ConnectedDeviceMacAddress = null; OnDisconnected?.Invoke(addressToDisconnect); // 延迟清理 Invoke(nameof(CleanupAfterDisconnect), 0.5f); } /// /// 断开连接后的清理工作 /// private void CleanupAfterDisconnect() { Log("执行断开连接后的清理..."); // 确保停止扫描 if (IsScanning) { StopScan(); } // 取消可能冲突的Invoke CancelInvoke(nameof(StopScan)); CancelInvoke(nameof(DelayedStartScan)); // 清理设备列表,为下次扫描做准备 DiscoveredDevices.Clear(); Log("断开连接清理完成,可以开始新的扫描"); } /// /// 完全重置蓝牙(断开连接并重新初始化) /// 用于解决断开后无法扫描到设备的问题 /// public void ResetBluetooth() { Log("开始完全重置蓝牙..."); // 停止扫描 if (IsScanning) { StopScan(); } // 断开连接 - 先发送0x70断开命令,再断开BLE连接 if (IsConnected) { string addressToDisconnect = ConnectedDeviceAddress; Log($"重置蓝牙: 正在断开连接 {addressToDisconnect}"); // 先通过BLE协议发送断开命令(0x70) if (BLECommunicationManager.Instance != null) { Log("重置蓝牙: 发送断开命令(0x70)到设备..."); BLECommunicationManager.Instance.Disconnect((success) => { Log($"重置蓝牙: 断开命令发送结果: {(success ? "成功" : "失败")}"); // 无论命令是否成功,都执行BLE断开 BluetoothLEHardwareInterface.DisconnectPeripheral(addressToDisconnect, (addr) => { }); }); } else { // 如果没有BLE通信管理器,直接断开BLE BluetoothLEHardwareInterface.DisconnectPeripheral(addressToDisconnect, (addr) => { }); } IsConnected = false; ConnectedDeviceAddress = null; ConnectedDeviceMacAddress = null; } // 取消所有Invoke CancelInvoke(); // 清理设备列表 DiscoveredDevices.Clear(); // 反初始化蓝牙 BluetoothLEHardwareInterface.DeInitialize(() => { IsInitialized = false; Log("蓝牙已反初始化,准备重新初始化..."); // 延迟重新初始化 Loom.QueueOnMainThread(() => { Invoke(nameof(ReinitializeBluetooth), 1f); }); }); } /// /// 重新初始化蓝牙(断开连接后使用,不触发自动连接) /// private void ReinitializeBluetooth() { Log("重新初始化蓝牙..."); BluetoothLEHardwareInterface.Initialize(true, false, () => { IsInitialized = true; Log("蓝牙重新初始化成功,现在可以扫描设备了"); OnInitialized?.Invoke(true); // 注意:这里不触发自动连接,避免干扰用户操作 }, (error) => { if (error.Contains("Service not found")) { Log("蓝牙重新初始化警告,继续..."); IsInitialized = true; OnInitialized?.Invoke(true); } else { Log($"蓝牙重新初始化失败: {error}"); OnError?.Invoke($"重新初始化失败: {error}"); } } ); } /// /// 反初始化蓝牙 /// public void DeInitialize() { if (IsConnected) { Disconnect(); } if (IsScanning) { StopScan(); } BluetoothLEHardwareInterface.DeInitialize(() => { IsInitialized = false; Log("蓝牙已反初始化"); }); } /// /// 添加或更新设备到列表 /// private void AddOrUpdateDevice(string address, string name, int rssi,byte[] bytes) { // 调试日志:显示所有发现的设备(包括无名称的) // Log($"扫描到设备: Name='{name}', Address={address}, RSSI={rssi}"); // 从广播数据中解析真实MAC地址(iOS端关键:address是UUID,MAC在bytes里) string macFromBroadcast = BluetoothDevice.ParseMacFromBytes(bytes); string effectiveAddress = macFromBroadcast ?? address; // 查找是否已存在(使用有效地址匹配,避免iOS端UUID变化导致重复添加) var existingDevice = DiscoveredDevices.Find(d => d.GetEffectiveAddress().ToUpper() == effectiveAddress.ToUpper()); if (existingDevice != null) { // 更新RSSI existingDevice.Rssi = rssi; // Log($"更新设备信号: {existingDevice.Name} [{effectiveAddress}] RSSI: {rssi}"); } else { // 过滤掉没有名称的设备 if (string.IsNullOrEmpty(name) || name == "No Name" || name == "Unknown") { return; } // 添加新设备(Address保留原始值用于Connect,MacFromBroadcast由构造函数自动解析) var newDevice = new BluetoothDevice(address, name, rssi,bytes); DiscoveredDevices.Add(newDevice); if (aimMac.ToUpper() == effectiveAddress.ToUpper()) { StopScan(); Connect(address); } OnDeviceFound?.Invoke(newDevice); } } /// /// 输出日志 /// private void Log(string message) { Debug.Log($"[BluetoothManager] {message}"); OnLog?.Invoke(message); } /// /// 通知连接成功并可通信 /// private void NotifyConnectedSuccess() { Log("蓝牙连接已就绪,可以开始通信"); OnConnectedSuccess?.Invoke(); } public bool ChangeAimMac(string mac) { aimMac = mac; if(aimMac=="") { return false; } if (IsConnected && mac.ToUpper() == (ConnectedDeviceMacAddress ?? ConnectedDeviceAddress).ToUpper()) { return true; } else { if (IsConnected && mac.ToUpper() != (ConnectedDeviceMacAddress ?? ConnectedDeviceAddress).ToUpper()) { Disconnect(); StartScan(10); } else { StartScan(10); } return false; } } } }