using UnityEngine;
using System;
using System.Collections.Generic;
///
/// 蓝牙设备信息
///
[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;
}
}
///
/// 蓝牙管理器 - 提供基础的蓝牙扫描、连接、断开功能
///
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 bool IsInitialized { get; private set; }
public bool IsScanning { get; private set; }
public bool IsConnected { get; private set; }
public string ConnectedDeviceAddress { get; private set; }
// 扫描到的设备列表
public List DiscoveredDevices { get; private set; } = new List();
// 上一次连接的设备地址
private const string LAST_DEVICE_ADDRESS_KEY = "LastConnectedDeviceAddress";
private const string LAST_DEVICE_NAME_KEY = "LastConnectedDeviceName";
// 是否自动连接
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;
}
}
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;
}
Log("正在初始化蓝牙...");
BluetoothLEHardwareInterface.Initialize(true, false,
() =>
{
IsInitialized = true;
Log("蓝牙初始化成功");
OnInitialized?.Invoke(true);
// 初始化成功后,延迟尝试自动连接上一次设备
// 延迟是为了让用户有机会先进行手动扫描
if (AutoConnect)
{
Log("将在3秒后尝试自动连接上一次设备...");
Invoke(nameof(TryAutoConnectDelayed), 3f);
}
},
(error) =>
{
// 忽略 "Service not found" 错误,这是插件内部问题,不影响功能
if (error.Contains("Service not found"))
{
Log($"蓝牙初始化警告: {error}");
Log("继续初始化...");
IsInitialized = true;
OnInitialized?.Invoke(true);
// 初始化成功后,延迟尝试自动连接上一次设备
if (AutoConnect)
{
Log("将在3秒后尝试自动连接上一次设备...");
Invoke(nameof(TryAutoConnectDelayed), 3f);
}
}
else
{
Log($"蓝牙初始化失败: {error}");
OnError?.Invoke($"初始化失败: {error}");
OnInitialized?.Invoke(false);
}
}
);
}
///
/// 延迟尝试自动连接(用于初始化后)
///
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 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;
///
/// 延迟自动连接(确保扫描完全停止后再连接)
///
private void DelayedAutoConnect()
{
if (!string.IsNullOrEmpty(_pendingAutoConnectAddress))
{
Log($"[BLE-DEBUG] 自动连接: 延迟连接 {_pendingAutoConnectAddress}");
Connect(_pendingAutoConnectAddress);
_pendingAutoConnectAddress = null;
}
}
///
/// 保存连接的设备信息
///
private void SaveLastConnectedDevice(string address, string name)
{
// 统一使用大写格式保存,确保地址格式一致
string normalizedAddress = address.ToUpper();
PlayerPrefs.SetString(LAST_DEVICE_ADDRESS_KEY, normalizedAddress);
PlayerPrefs.SetString(LAST_DEVICE_NAME_KEY, name);
PlayerPrefs.Save();
Log($"保存设备连接记录: {name} [{normalizedAddress}]");
}
///
/// 清除设备连接记录
///
public void ClearLastConnectedDevice()
{
PlayerPrefs.DeleteKey(LAST_DEVICE_ADDRESS_KEY);
PlayerPrefs.DeleteKey(LAST_DEVICE_NAME_KEY);
PlayerPrefs.Save();
Log("清除设备连接记录");
}
///
/// 开始扫描蓝牙设备
///
/// 扫描超时时间(秒),默认10秒
public void StartScan(float timeout = 10f)
{
if (!IsInitialized)
{
OnError?.Invoke("蓝牙未初始化,请先调用Initialize()");
return;
}
// 取消自动连接,避免干扰手动扫描
CancelInvoke(nameof(TryAutoConnectDelayed));
if (IsScanning)
{
Log("已经在扫描中,先停止当前扫描...");
StopScan();
}
// 如果还在连接状态,先断开
if (IsConnected)
{
Log("警告: 扫描时仍处于连接状态,先断开连接...");
Disconnect();
// 延迟一点再开始扫描
Invoke(nameof(DelayedStartScan), 1f);
return;
}
// 清空之前的设备列表
DiscoveredDevices.Clear();
IsScanning = true;
Log($"开始扫描蓝牙设备 (超时: {timeout}秒)...");
// 开始扫描
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);
}
///
/// 延迟开始扫描(用于断开连接后)
///
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);
}
///
/// 停止扫描
///
public void StopScan()
{
if (!IsScanning) return;
IsScanning = false;
// 取消所有扫描相关的Invoke
CancelInvoke(nameof(StopScan));
CancelInvoke(nameof(DelayedStartScan));
CancelInvoke(nameof(TryAutoConnectDelayed));
BluetoothLEHardwareInterface.StopScan();
Log("停止扫描蓝牙设备");
}
///
/// 连接指定设备
///
/// 设备地址
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}");
}
}
);
}
///
/// 按名称连接设备
///
/// 设备名称
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()
{
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;
OnDisconnected?.Invoke(addressToDisconnect);
// 延迟清理
Invoke(nameof(CleanupAfterDisconnect), 0.5f);
}
///
/// 断开连接后的清理工作
///
private void CleanupAfterDisconnect()
{
Log("执行断开连接后的清理...");
// 确保停止扫描
if (IsScanning)
{
StopScan();
}
// 取消可能冲突的Invoke
CancelInvoke(nameof(StopScan));
CancelInvoke(nameof(DelayedStartScan));
CancelInvoke(nameof(TryAutoConnectDelayed));
// 清理设备列表,为下次扫描做准备
DiscoveredDevices.Clear();
Log("断开连接清理完成,可以开始新的扫描");
}
///
/// 完全重置蓝牙(断开连接并重新初始化)
/// 用于解决断开后无法扫描到设备的问题
///
public void ResetBluetooth()
{
Log("开始完全重置蓝牙...");
// 保存上一次连接的设备信息
string lastAddress = PlayerPrefs.GetString(LAST_DEVICE_ADDRESS_KEY, "");
string lastName = PlayerPrefs.GetString(LAST_DEVICE_NAME_KEY, "");
// 停止扫描
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);
});
});
}
///
/// 重新初始化蓝牙(断开连接后使用,不触发自动连接)
///
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)
{
// 调试日志:显示所有发现的设备(包括无名称的)
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}");
OnDeviceFound?.Invoke(newDevice);
}
}
///
/// 输出日志
///
private void Log(string message)
{
Debug.Log($"[BluetoothManager] {message}");
OnLog?.Invoke(message);
}
///
/// 通知连接成功并可通信
///
private void NotifyConnectedSuccess()
{
Log("蓝牙连接已就绪,可以开始通信");
OnConnectedSuccess?.Invoke();
}
}