987 lines
34 KiB
C#
987 lines
34 KiB
C#
using UnityEngine;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using Kill.Core;
|
||
using Kill.UI.Components;
|
||
|
||
namespace Kill.Bluetooth
|
||
{
|
||
/// <summary>
|
||
/// 蓝牙设备信息
|
||
/// </summary>
|
||
[Serializable]
|
||
public class BluetoothDevice
|
||
{
|
||
public string Address; // 设备地址
|
||
public string Name; // 设备名称
|
||
public int Rssi; // 信号强度
|
||
|
||
public BluetoothDevice(string address, string name, int rssi = 0)
|
||
{
|
||
Address = address;
|
||
Name = name;
|
||
Rssi = rssi;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 蓝牙管理器 - 提供基础的蓝牙扫描、连接、断开功能
|
||
/// </summary>
|
||
public class BluetoothManager : MonoBehaviour
|
||
{
|
||
public static BluetoothManager Instance { get; private set; }
|
||
|
||
// 事件定义
|
||
public event Action<bool> OnInitialized; // 初始化完成事件
|
||
public event Action<BluetoothDevice> OnDeviceFound; // 发现设备事件
|
||
public event Action<string> OnConnected; // 连接成功事件 (参数: 设备地址)
|
||
public event Action<string> OnConnectFailed; // 连接失败事件 (参数: 设备地址)
|
||
public event Action<string> OnDisconnected; // 断开连接事件 (参数: 设备地址)
|
||
public event Action<string> OnError; // 错误事件
|
||
public event Action<string> 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; }
|
||
private string aimMac = "";
|
||
// 扫描到的设备列表
|
||
public List<BluetoothDevice> DiscoveredDevices { get; private set; } = new List<BluetoothDevice>();
|
||
|
||
// 是否自动连接
|
||
public bool AutoConnect = true;
|
||
|
||
// 连接超时设置
|
||
public float ConnectionTimeout = 10f; // 连接超时时间(秒)
|
||
private float _connectionTimer;
|
||
private bool _isConnecting;
|
||
private string _connectingAddress;
|
||
|
||
private void Awake()
|
||
{
|
||
if (Instance == null)
|
||
{
|
||
Instance = this;
|
||
DontDestroyOnLoad(gameObject);
|
||
}
|
||
else
|
||
{
|
||
Destroy(gameObject);
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (Instance == this)
|
||
{
|
||
Instance = null;
|
||
}
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化蓝牙(带自动启用)
|
||
/// </summary>
|
||
public void Initialize()
|
||
{
|
||
if (IsInitialized)
|
||
{
|
||
Log("蓝牙已经初始化");
|
||
OnInitialized?.Invoke(true);
|
||
return;
|
||
}
|
||
|
||
Log("正在初始化蓝牙...");
|
||
|
||
// 先检查蓝牙是否开启,如果没有则尝试启用
|
||
CheckAndEnableBluetooth(() =>
|
||
{
|
||
// 蓝牙已启用,执行初始化
|
||
DoInitialize();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查并启用蓝牙
|
||
/// </summary>
|
||
private void CheckAndEnableBluetooth(System.Action onBluetoothReady)
|
||
{
|
||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
using (AndroidJavaClass bluetoothAdapterClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter"))
|
||
{
|
||
AndroidJavaObject bluetoothAdapter = bluetoothAdapterClass.CallStatic<AndroidJavaObject>("getDefaultAdapter");
|
||
|
||
if (bluetoothAdapter == null)
|
||
{
|
||
OnError?.Invoke("设备不支持蓝牙");
|
||
OnInitialized?.Invoke(false);
|
||
return;
|
||
}
|
||
|
||
bool isEnabled = bluetoothAdapter.Call<bool>("isEnabled");
|
||
|
||
if (!isEnabled)
|
||
{
|
||
Log("蓝牙未开启,尝试启用...");
|
||
|
||
// 尝试静默启用蓝牙
|
||
bool enableSuccess = bluetoothAdapter.Call<bool>("enable");
|
||
|
||
if (enableSuccess)
|
||
{
|
||
Log("正在启用蓝牙,等待...");
|
||
// 等待蓝牙启用
|
||
StartCoroutine(WaitForBluetoothEnabled(onBluetoothReady));
|
||
}
|
||
else
|
||
{
|
||
// 静默启用失败,请求用户启用
|
||
RequestUserEnableBluetooth(onBluetoothReady);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Log("蓝牙已开启");
|
||
onBluetoothReady?.Invoke();
|
||
}
|
||
}
|
||
#elif UNITY_IOS && !UNITY_EDITOR
|
||
// iOS 检查蓝牙状态
|
||
CheckBluetoothStateIOS(onBluetoothReady);
|
||
#else
|
||
// 其他平台直接执行初始化
|
||
onBluetoothReady?.Invoke();
|
||
#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();
|
||
|
||
/// <summary>
|
||
/// iOS 检查蓝牙状态
|
||
/// 0 = Unknown, 1 = Resetting, 2 = Unsupported, 3 = Unauthorized, 4 = PoweredOff, 5 = PoweredOn
|
||
/// </summary>
|
||
private void CheckBluetoothStateIOS(System.Action onBluetoothReady)
|
||
{
|
||
int state = GetBluetoothStateIOS();
|
||
Log($"iOS 蓝牙状态: {state}");
|
||
|
||
// 5 = PoweredOn (蓝牙已开启)
|
||
if (state == 5)
|
||
{
|
||
Log("iOS 蓝牙已开启");
|
||
onBluetoothReady?.Invoke();
|
||
}
|
||
// 4 = PoweredOff (蓝牙关闭)
|
||
else if (state == 4)
|
||
{
|
||
Log("iOS 蓝牙未开启,提示用户");
|
||
// iOS 不能自动打开蓝牙,只能提示用户去设置中开启
|
||
ShowIOSTurnOnBluetoothPrompt();
|
||
OnError?.Invoke("请在系统设置中开启蓝牙");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
// 3 = Unauthorized (未授权)
|
||
else if (state == 3)
|
||
{
|
||
Log("iOS 蓝牙未授权");
|
||
OnError?.Invoke("请在设置中允许使用蓝牙");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
// 2 = Unsupported (不支持蓝牙)
|
||
else if (state == 2)
|
||
{
|
||
Log("设备不支持蓝牙");
|
||
OnError?.Invoke("设备不支持蓝牙");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
// 其他状态
|
||
else
|
||
{
|
||
Log($"iOS 蓝牙状态未知: {state},尝试继续初始化");
|
||
onBluetoothReady?.Invoke();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示 iOS 开启蓝牙提示
|
||
/// </summary>
|
||
private void ShowIOSTurnOnBluetoothPrompt()
|
||
{
|
||
// 可以在这里显示一个弹窗,引导用户去设置
|
||
// 或者使用原生插件跳转到设置页面
|
||
OpenBluetoothSettingsIOS();
|
||
}
|
||
#endif
|
||
|
||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
/// <summary>
|
||
/// 等待蓝牙启用
|
||
/// </summary>
|
||
private System.Collections.IEnumerator WaitForBluetoothEnabled(System.Action onBluetoothReady)
|
||
{
|
||
float timeout = 5f;
|
||
float timer = 0f;
|
||
|
||
while (timer < timeout)
|
||
{
|
||
using (AndroidJavaClass bluetoothAdapterClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter"))
|
||
{
|
||
AndroidJavaObject bluetoothAdapter = bluetoothAdapterClass.CallStatic<AndroidJavaObject>("getDefaultAdapter");
|
||
if (bluetoothAdapter != null && bluetoothAdapter.Call<bool>("isEnabled"))
|
||
{
|
||
Log("蓝牙已成功启用");
|
||
onBluetoothReady?.Invoke();
|
||
yield break;
|
||
}
|
||
}
|
||
|
||
yield return new WaitForSeconds(0.5f);
|
||
timer += 0.5f;
|
||
}
|
||
|
||
Log("等待蓝牙启用超时");
|
||
OnError?.Invoke("蓝牙启用超时");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 请求用户启用蓝牙
|
||
/// </summary>
|
||
private void RequestUserEnableBluetooth(System.Action onBluetoothReady)
|
||
{
|
||
Log("请求用户启用蓝牙...");
|
||
|
||
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
||
using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
|
||
{
|
||
AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.bluetooth.adapter.action.REQUEST_ENABLE");
|
||
currentActivity.Call("startActivityForResult", intent, 1);
|
||
}
|
||
|
||
// 等待用户响应
|
||
StartCoroutine(WaitForUserEnableBluetooth(onBluetoothReady));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 等待用户启用蓝牙
|
||
/// </summary>
|
||
private System.Collections.IEnumerator WaitForUserEnableBluetooth(System.Action onBluetoothReady)
|
||
{
|
||
float timeout = 30f;
|
||
float timer = 0f;
|
||
|
||
while (timer < timeout)
|
||
{
|
||
using (AndroidJavaClass bluetoothAdapterClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter"))
|
||
{
|
||
AndroidJavaObject bluetoothAdapter = bluetoothAdapterClass.CallStatic<AndroidJavaObject>("getDefaultAdapter");
|
||
if (bluetoothAdapter != null && bluetoothAdapter.Call<bool>("isEnabled"))
|
||
{
|
||
Log("用户已启用蓝牙");
|
||
onBluetoothReady?.Invoke();
|
||
yield break;
|
||
}
|
||
}
|
||
|
||
yield return new WaitForSeconds(0.5f);
|
||
timer += 0.5f;
|
||
}
|
||
|
||
Log("用户未启用蓝牙或超时");
|
||
OnError?.Invoke("请启用蓝牙后重试");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// 执行蓝牙初始化
|
||
/// </summary>
|
||
// 标记是否已完成初始化
|
||
private bool _isFullyInitialized = false;
|
||
|
||
private void DoInitialize()
|
||
{
|
||
_isFullyInitialized = false;
|
||
|
||
BluetoothLEHardwareInterface.Initialize(true, false,
|
||
() =>
|
||
{
|
||
IsInitialized = true;
|
||
_isFullyInitialized = true;
|
||
Log("蓝牙初始化成功");
|
||
OnInitialized?.Invoke(true);
|
||
},
|
||
(error) =>
|
||
{
|
||
// 忽略 "Service not found" 错误,这是插件内部问题,不影响功能
|
||
if (error.Contains("Service not found"))
|
||
{
|
||
Log($"蓝牙初始化警告: {error}");
|
||
Log("继续初始化...");
|
||
IsInitialized = true;
|
||
_isFullyInitialized = true;
|
||
OnInitialized?.Invoke(true);
|
||
}
|
||
// 如果已经初始化完成,这是运行时错误,不是初始化错误
|
||
else if (_isFullyInitialized)
|
||
{
|
||
Log($"蓝牙运行时错误: {error}");
|
||
OnError?.Invoke(error);
|
||
}
|
||
else
|
||
{
|
||
Log($"蓝牙初始化失败: {error}");
|
||
OnError?.Invoke($"初始化失败: {error}");
|
||
OnInitialized?.Invoke(false);
|
||
}
|
||
},
|
||
needLocation: true
|
||
);
|
||
}
|
||
|
||
// /// <summary>
|
||
// /// 延迟尝试自动连接(用于初始化后)
|
||
// /// </summary>
|
||
// private void TryAutoConnectDelayed()
|
||
// {
|
||
// // 如果用户已经开始扫描或连接,跳过自动连接
|
||
// if (IsScanning || IsConnected || _isConnecting)
|
||
// {
|
||
// Log("用户正在进行扫描或连接,跳过自动连接");
|
||
// return;
|
||
// }
|
||
|
||
// TryAutoConnect();
|
||
// }
|
||
|
||
// /// <summary>
|
||
// /// 尝试自动连接上一次连接的设备
|
||
// /// </summary>
|
||
// 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);
|
||
// }
|
||
|
||
/// <summary>
|
||
/// 为自动连接扫描设备
|
||
/// </summary>
|
||
private void StartScanForAutoConnect(string targetAddress)
|
||
{
|
||
if (!IsInitialized)
|
||
{
|
||
Log("蓝牙未初始化,无法扫描");
|
||
return;
|
||
}
|
||
|
||
Log("[BLE-DEBUG] 自动连接: 开始扫描...");
|
||
|
||
// 清空设备列表
|
||
DiscoveredDevices.Clear();
|
||
|
||
// 扫描5秒
|
||
BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,
|
||
(address, name) =>
|
||
{
|
||
// 先添加到设备列表
|
||
AddOrUpdateDevice(address, name, 0);
|
||
|
||
// 检查是否是要找的设备(统一使用大写比较)
|
||
if (address.ToUpper() == targetAddress.ToUpper())
|
||
{
|
||
Log($"[BLE-DEBUG] 自动连接: 找到设备 {name}");
|
||
BluetoothLEHardwareInterface.StopScan();
|
||
// 延迟100ms再连接,确保扫描完全停止(与手动连接流程一致)
|
||
_pendingAutoConnectAddress = targetAddress;
|
||
Invoke(nameof(DelayedAutoConnect), 0.1f);
|
||
}
|
||
},
|
||
(address, name, rssi, bytes) =>
|
||
{
|
||
// 先添加到设备列表
|
||
AddOrUpdateDevice(address, name, rssi);
|
||
|
||
// 检查是否是要找的设备(统一使用大写比较)
|
||
if (address.ToUpper() == targetAddress.ToUpper())
|
||
{
|
||
Log($"[BLE-DEBUG] 自动连接: 找到设备 {name}, RSSI: {rssi}");
|
||
BluetoothLEHardwareInterface.StopScan();
|
||
// 延迟100ms再连接,确保扫描完全停止(与手动连接流程一致)
|
||
_pendingAutoConnectAddress = targetAddress;
|
||
Invoke(nameof(DelayedAutoConnect), 0.1f);
|
||
}
|
||
},
|
||
true
|
||
);
|
||
|
||
// 5秒后停止扫描
|
||
Invoke(nameof(StopScan), 5f);
|
||
}
|
||
|
||
// 用于自动连接的临时地址存储
|
||
private string _pendingAutoConnectAddress;
|
||
|
||
/// <summary>
|
||
/// 延迟自动连接(确保扫描完全停止后再连接)
|
||
/// </summary>
|
||
private void DelayedAutoConnect()
|
||
{
|
||
if (!string.IsNullOrEmpty(_pendingAutoConnectAddress))
|
||
{
|
||
Log($"[BLE-DEBUG] 自动连接: 延迟连接 {_pendingAutoConnectAddress}");
|
||
Connect(_pendingAutoConnectAddress);
|
||
_pendingAutoConnectAddress = null;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 开始扫描蓝牙设备
|
||
/// </summary>
|
||
/// <param name="timeout">扫描超时时间(秒),默认10秒</param>
|
||
public void StartScan(float timeout = 999f)
|
||
{
|
||
if (!IsInitialized)
|
||
{
|
||
OnError?.Invoke("蓝牙未初始化,请先调用Initialize()");
|
||
return;
|
||
}
|
||
|
||
if (IsScanning)
|
||
{
|
||
Log("已经在扫描中,先停止当前扫描...");
|
||
StopScan();
|
||
}
|
||
|
||
// 如果还在连接状态,先断开
|
||
if (IsConnected)
|
||
{
|
||
Log("警告: 扫描时仍处于连接状态,先断开连接...");
|
||
Disconnect();
|
||
// 延迟一点再开始扫描
|
||
Invoke(nameof(DelayedStartScan), 1f);
|
||
return;
|
||
}
|
||
|
||
// 清空之前的设备列表
|
||
DiscoveredDevices.Clear();
|
||
IsScanning = true;
|
||
|
||
Log($"开始扫描蓝牙设备 (超时: {timeout}秒)...");
|
||
OnStartScan?.Invoke();
|
||
// 开始扫描
|
||
BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,
|
||
// 回调1:基础设备信息(地址和名称)
|
||
(address, name) =>
|
||
{
|
||
AddOrUpdateDevice(address, name, 0);
|
||
},
|
||
// 回调2:包含RSSI和制造商数据
|
||
(address, name, rssi, bytes) =>
|
||
{
|
||
AddOrUpdateDevice(address, name, rssi);
|
||
},
|
||
true // 允许不带有制造商数据的RSSI
|
||
);
|
||
|
||
// 设置超时自动停止
|
||
Invoke(nameof(StopScan), timeout);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延迟开始扫描(用于断开连接后)
|
||
/// </summary>
|
||
private void DelayedStartScan()
|
||
{
|
||
Log("延迟扫描开始...");
|
||
// 清空设备列表
|
||
DiscoveredDevices.Clear();
|
||
IsScanning = true;
|
||
|
||
BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null,
|
||
(address, name) =>
|
||
{
|
||
AddOrUpdateDevice(address, name, 0);
|
||
},
|
||
(address, name, rssi, bytes) =>
|
||
{
|
||
AddOrUpdateDevice(address, name, rssi);
|
||
},
|
||
true
|
||
);
|
||
|
||
Invoke(nameof(StopScan), 10f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止扫描
|
||
/// </summary>
|
||
public void StopScan()
|
||
{
|
||
|
||
if (!IsScanning) return;
|
||
IsScanning = false;
|
||
OnStopScan?.Invoke();
|
||
// 取消所有扫描相关的Invoke
|
||
CancelInvoke(nameof(StopScan));
|
||
CancelInvoke(nameof(DelayedStartScan));
|
||
|
||
BluetoothLEHardwareInterface.StopScan();
|
||
Log("停止扫描蓝牙设备");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连接指定设备
|
||
/// </summary>
|
||
/// <param name="deviceAddress">设备地址</param>
|
||
public void Connect(string deviceAddress)
|
||
{
|
||
if (!IsInitialized)
|
||
{
|
||
OnError?.Invoke("蓝牙未初始化");
|
||
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";
|
||
//SaveLastConnectedDevice(address, deviceName);
|
||
|
||
OnConnected?.Invoke(address);
|
||
|
||
// 延迟通知连接成功并可通信
|
||
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;
|
||
Log($"设备断开连接: {disconnectAddress}");
|
||
OnDisconnected?.Invoke(disconnectAddress);
|
||
|
||
// 执行清理
|
||
CleanupAfterDisconnect();
|
||
}
|
||
else
|
||
{
|
||
Log($"收到未处理的断开回调: {disconnectAddress}, 当前连接状态: IsConnected={IsConnected}");
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按名称连接设备
|
||
/// </summary>
|
||
/// <param name="deviceName">设备名称</param>
|
||
public void ConnectByName(string deviceName)
|
||
{
|
||
var device = DiscoveredDevices.Find(d => d.Name == deviceName);
|
||
if (device != null)
|
||
{
|
||
Connect(device.Address);
|
||
}
|
||
else
|
||
{
|
||
OnError?.Invoke($"未找到设备: {deviceName}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 断开当前连接(带协议通知)
|
||
/// 先发送0x70断开命令给设备,再断开BLE连接
|
||
/// </summary>
|
||
public void Disconnect()
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行BLE层断开连接
|
||
/// </summary>
|
||
private void PerformBLEDisconnect(string addressToDisconnect)
|
||
{
|
||
Log($"执行BLE断开: {addressToDisconnect}");
|
||
|
||
BluetoothLEHardwareInterface.DisconnectPeripheral(addressToDisconnect,
|
||
(address) =>
|
||
{
|
||
Log($"BLE断开连接回调: {address}");
|
||
}
|
||
);
|
||
|
||
// 立即清理状态
|
||
IsConnected = false;
|
||
ConnectedDeviceAddress = null;
|
||
OnDisconnected?.Invoke(addressToDisconnect);
|
||
|
||
// 延迟清理
|
||
Invoke(nameof(CleanupAfterDisconnect), 0.5f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 断开连接后的清理工作
|
||
/// </summary>
|
||
private void CleanupAfterDisconnect()
|
||
{
|
||
Log("执行断开连接后的清理...");
|
||
|
||
// 确保停止扫描
|
||
if (IsScanning)
|
||
{
|
||
StopScan();
|
||
}
|
||
|
||
// 取消可能冲突的Invoke
|
||
CancelInvoke(nameof(StopScan));
|
||
CancelInvoke(nameof(DelayedStartScan));
|
||
|
||
// 清理设备列表,为下次扫描做准备
|
||
DiscoveredDevices.Clear();
|
||
|
||
Log("断开连接清理完成,可以开始新的扫描");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 完全重置蓝牙(断开连接并重新初始化)
|
||
/// 用于解决断开后无法扫描到设备的问题
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
// 取消所有Invoke
|
||
CancelInvoke();
|
||
|
||
// 清理设备列表
|
||
DiscoveredDevices.Clear();
|
||
|
||
// 反初始化蓝牙
|
||
BluetoothLEHardwareInterface.DeInitialize(() =>
|
||
{
|
||
IsInitialized = false;
|
||
Log("蓝牙已反初始化,准备重新初始化...");
|
||
|
||
// 延迟重新初始化
|
||
Loom.QueueOnMainThread(() =>
|
||
{
|
||
Invoke(nameof(ReinitializeBluetooth), 1f);
|
||
});
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重新初始化蓝牙(断开连接后使用,不触发自动连接)
|
||
/// </summary>
|
||
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}");
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 反初始化蓝牙
|
||
/// </summary>
|
||
public void DeInitialize()
|
||
{
|
||
if (IsConnected)
|
||
{
|
||
Disconnect();
|
||
}
|
||
|
||
if (IsScanning)
|
||
{
|
||
StopScan();
|
||
}
|
||
|
||
BluetoothLEHardwareInterface.DeInitialize(() =>
|
||
{
|
||
IsInitialized = false;
|
||
Log("蓝牙已反初始化");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加或更新设备到列表
|
||
/// </summary>
|
||
private void AddOrUpdateDevice(string address, string name, int rssi)
|
||
{
|
||
// 调试日志:显示所有发现的设备(包括无名称的)
|
||
// Log($"扫描到设备: Name='{name}', Address={address}, RSSI={rssi}");
|
||
|
||
// 查找是否已存在
|
||
var existingDevice = DiscoveredDevices.Find(d => d.Address.ToUpper() == address.ToUpper());
|
||
if (existingDevice != null)
|
||
{
|
||
// 更新RSSI
|
||
existingDevice.Rssi = rssi;
|
||
// Log($"更新设备信号: {existingDevice.Name} [{address}] RSSI: {rssi}");
|
||
}
|
||
else
|
||
{
|
||
// 过滤掉没有名称的设备
|
||
if (string.IsNullOrEmpty(name) || name == "No Name" || name == "Unknown")
|
||
{
|
||
// Log($"过滤无名称设备: [{address}]");
|
||
return;
|
||
}
|
||
|
||
// 添加新设备
|
||
var newDevice = new BluetoothDevice(address, name, rssi);
|
||
DiscoveredDevices.Add(newDevice);
|
||
Log($"发现新设备: {name} [{address}] RSSI: {rssi}");
|
||
if (aimMac.ToUpper() == address.ToUpper())
|
||
{
|
||
StopScan();
|
||
|
||
Connect(address);
|
||
}
|
||
OnDeviceFound?.Invoke(newDevice);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 输出日志
|
||
/// </summary>
|
||
private void Log(string message)
|
||
{
|
||
Debug.Log($"[BluetoothManager] {message}");
|
||
OnLog?.Invoke(message);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通知连接成功并可通信
|
||
/// </summary>
|
||
private void NotifyConnectedSuccess()
|
||
{
|
||
Log("蓝牙连接已就绪,可以开始通信");
|
||
OnConnectedSuccess?.Invoke();
|
||
}
|
||
|
||
public bool ChangeAimMac(string mac)
|
||
{
|
||
aimMac = mac;
|
||
if(aimMac=="")
|
||
{
|
||
return false;
|
||
}
|
||
if (IsConnected && mac.ToUpper() == ConnectedDeviceAddress.ToUpper())
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
if (IsConnected && mac.ToUpper() != ConnectedDeviceAddress.ToUpper())
|
||
{
|
||
Disconnect();
|
||
StartScan(10);
|
||
}
|
||
else
|
||
{
|
||
StartScan(10);
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|