770 lines
24 KiB
C#
770 lines
24 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
/// <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 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<BluetoothDevice> DiscoveredDevices { get; private set; } = new List<BluetoothDevice>();
|
|||
|
|
|
|||
|
|
// 上一次连接的设备地址
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化蓝牙
|
|||
|
|
/// </summary>
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <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>
|
|||
|
|
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}]");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清除设备连接记录
|
|||
|
|
/// </summary>
|
|||
|
|
public void ClearLastConnectedDevice()
|
|||
|
|
{
|
|||
|
|
PlayerPrefs.DeleteKey(LAST_DEVICE_ADDRESS_KEY);
|
|||
|
|
PlayerPrefs.DeleteKey(LAST_DEVICE_NAME_KEY);
|
|||
|
|
PlayerPrefs.Save();
|
|||
|
|
Log("清除设备连接记录");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 开始扫描蓝牙设备
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="timeout">扫描超时时间(秒),默认10秒</param>
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <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;
|
|||
|
|
|
|||
|
|
// 取消所有扫描相关的Invoke
|
|||
|
|
CancelInvoke(nameof(StopScan));
|
|||
|
|
CancelInvoke(nameof(DelayedStartScan));
|
|||
|
|
CancelInvoke(nameof(TryAutoConnectDelayed));
|
|||
|
|
|
|||
|
|
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));
|
|||
|
|
CancelInvoke(nameof(TryAutoConnectDelayed));
|
|||
|
|
|
|||
|
|
// 清理设备列表,为下次扫描做准备
|
|||
|
|
DiscoveredDevices.Clear();
|
|||
|
|
|
|||
|
|
Log("断开连接清理完成,可以开始新的扫描");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 完全重置蓝牙(断开连接并重新初始化)
|
|||
|
|
/// 用于解决断开后无法扫描到设备的问题
|
|||
|
|
/// </summary>
|
|||
|
|
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);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <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}");
|
|||
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|