fix(bluetooth,ui): 修复蓝牙关闭后的断开链路与响应数据空引用
- 关蓝牙时跳过0x70协议告别帧与扫描(BluetoothLeScanner为null会抛NPE中断主页Init) - 初始化前检查蓝牙开关静默跳过,错误回调不再误报初始化失败,断开清理不在蓝牙关闭时自动重扫 - 错误/超时响应统一携带空Data,修复超时回调BitConverter.ToString(null)崩溃 - 主页Init增加异常兜底:保证Loading收尾并记录完整异常
This commit is contained in:
parent
320ece473f
commit
99ffc19f60
@ -2449,7 +2449,7 @@ namespace Kill.Bluetooth
|
||||
if (!CheckConnection())
|
||||
{
|
||||
LogError($"[BLE-DEBUG] 蓝牙未就绪,无法发送指令: {description}");
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR });
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR, Data = new byte[0] });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2465,7 +2465,7 @@ namespace Kill.Bluetooth
|
||||
if (!CheckConnection())
|
||||
{
|
||||
LogError("[BLE-DEBUG] CheckConnection failed, invoking callback with error");
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR });
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR, Data = new byte[0] });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2516,7 +2516,7 @@ namespace Kill.Bluetooth
|
||||
{
|
||||
LogError($"发送帧异常: {ex.Message}");
|
||||
IsWaitingResponse = false;
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR });
|
||||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR, Data = new byte[0] });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2963,7 +2963,9 @@ namespace Kill.Bluetooth
|
||||
|
||||
var timeoutResponse = new BLEResponse
|
||||
{
|
||||
Status = BLEConstants.STATUS_TIMEOUT
|
||||
Status = BLEConstants.STATUS_TIMEOUT,
|
||||
// 超时无数据,给空数组避免回调里 BitConverter.ToString(response.Data) 抛 ArgumentNullException
|
||||
Data = new byte[0]
|
||||
};
|
||||
|
||||
_pendingCallback?.Invoke(timeoutResponse);
|
||||
|
||||
@ -202,6 +202,18 @@ namespace Kill.Bluetooth
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
// 安卓:蓝牙已被系统关闭时直接静默跳过。
|
||||
// 断开清理/自动重连等后台流程会反复触发初始化,若继续走到 CheckAndEnableBluetooth
|
||||
// 会弹"蓝牙未开启"Toast 并广播 OnError,造成关蓝牙后一连串误报。
|
||||
// 用户主动触发的初始化走 ForceInitialize,仍能得到提示。
|
||||
if (!CheckIfBluetoothIsOn())
|
||||
{
|
||||
Log("蓝牙未开启,跳过蓝牙初始化");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Log("正在初始化蓝牙...");
|
||||
|
||||
// 先检查蓝牙是否开启,如果没有则尝试启用
|
||||
@ -218,7 +230,10 @@ namespace Kill.Bluetooth
|
||||
public void ForceInitialize()
|
||||
{
|
||||
_userDeniedBluetooth = false;
|
||||
Initialize();
|
||||
// 用户主动触发:不走 Initialize 的静默跳过守卫,
|
||||
// 蓝牙未开启时由 CheckAndEnableBluetooth 给出提示
|
||||
Log("正在初始化蓝牙...");
|
||||
CheckAndEnableBluetooth(DoInitialize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -476,7 +491,8 @@ namespace Kill.Bluetooth
|
||||
}
|
||||
if (IsConnected)
|
||||
{
|
||||
Disconnect();
|
||||
// 蓝牙已被系统关闭,0x70 协议告别帧发不出去,跳过直接清理本地状态
|
||||
Disconnect(sendProtocolCommand: false);
|
||||
}
|
||||
if (IsScanning)
|
||||
{
|
||||
@ -595,6 +611,13 @@ namespace Kill.Bluetooth
|
||||
}
|
||||
else
|
||||
{
|
||||
// 蓝牙已被系统关闭时,插件所有操作(写入/扫描/断开)的失败都会进入这个全局错误回调,
|
||||
// 此刻并非初始化失败,状态已由 MonitorBluetoothState 清理过,只记录不广播,避免误报
|
||||
if (!CheckIfBluetoothIsOn())
|
||||
{
|
||||
Log($"蓝牙已关闭,忽略蓝牙错误: {error}");
|
||||
return;
|
||||
}
|
||||
Log($"蓝牙初始化失败: {error}");
|
||||
_enableBtCoroutine = null;
|
||||
OnError?.Invoke($"初始化失败: {error}");
|
||||
@ -676,6 +699,14 @@ namespace Kill.Bluetooth
|
||||
/// <param name="timeout">扫描超时时间(秒),默认10秒</param>
|
||||
public void StartScan(float timeout = 999f)
|
||||
{
|
||||
// 蓝牙已被系统关闭时直接跳过:此时 BluetoothLeScanner 为 null,
|
||||
// 插件扫描调用会抛 NullPointerException(曾导致主页 Init 中断、设备状态不刷新)
|
||||
if (!CheckIfBluetoothIsOn())
|
||||
{
|
||||
Log("蓝牙未开启,跳过扫描");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsInitialized)
|
||||
{
|
||||
Log("蓝牙未初始化,自动触发初始化流程...");
|
||||
@ -693,6 +724,12 @@ namespace Kill.Bluetooth
|
||||
/// </summary>
|
||||
private void DoStartScan(float timeout)
|
||||
{
|
||||
if (!CheckIfBluetoothIsOn())
|
||||
{
|
||||
Log("蓝牙未开启,跳过扫描");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsScanning)
|
||||
{
|
||||
Log("已经在扫描中,先停止当前扫描...");
|
||||
@ -907,7 +944,7 @@ namespace Kill.Bluetooth
|
||||
/// 断开当前连接(带协议通知)
|
||||
/// 先发送0x70断开命令给设备,再断开BLE连接
|
||||
/// </summary>
|
||||
public void Disconnect(bool backHome=false)
|
||||
public void Disconnect(bool backHome=false, bool sendProtocolCommand=true)
|
||||
{
|
||||
needBackHome=backHome;
|
||||
if (!IsConnected)
|
||||
@ -933,21 +970,23 @@ namespace Kill.Bluetooth
|
||||
}
|
||||
|
||||
// 先通过BLE协议发送断开命令(0x70)
|
||||
Log($"检查BLECommunicationManager: Instance={(BLECommunicationManager.Instance != null ? "存在" : "null")}");
|
||||
if (BLECommunicationManager.Instance != null)
|
||||
if (sendProtocolCommand && BLECommunicationManager.Instance != null)
|
||||
{
|
||||
Log("发送断开命令(0x70)到设备...");
|
||||
BLECommunicationManager.Instance.Disconnect((success) =>
|
||||
{
|
||||
Log($"断开命令发送结果: {(success ? "成功" : "失败")}");
|
||||
// 0x70 设备不会回复,success 仅表示已提交插件写入,不代表设备已收到
|
||||
Log($"断开命令已提交: {(success ? "是" : "否")}");
|
||||
// 无论命令是否成功,都执行BLE断开
|
||||
PerformBLEDisconnect(addressToDisconnect);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("BLECommunicationManager.Instance 为 null,跳过0x70命令,直接断开BLE");
|
||||
// 如果没有BLE通信管理器,直接断开BLE
|
||||
Log(!sendProtocolCommand
|
||||
? "蓝牙不可用,跳过0x70命令,直接断开BLE"
|
||||
: "BLECommunicationManager.Instance 为 null,跳过0x70命令,直接断开BLE");
|
||||
// 如果没有BLE通信管理器或蓝牙不可用,直接断开BLE
|
||||
PerformBLEDisconnect(addressToDisconnect);
|
||||
}
|
||||
}
|
||||
@ -1000,7 +1039,9 @@ namespace Kill.Bluetooth
|
||||
|
||||
// ChangeAimMac 切换设备时是 Disconnect + StartScan 同步调用,
|
||||
// 本次清理会停掉刚启动的扫描,这里若仍有连接目标则自动重新扫描,避免连接流程中断
|
||||
if (!string.IsNullOrEmpty(aimMac) && !IsConnected)
|
||||
// 蓝牙已被系统关闭时不重扫(扫描只会触发一轮失败的初始化),
|
||||
// 等蓝牙重新打开后由 MonitorBluetoothState 的自动初始化流程接管
|
||||
if (!string.IsNullOrEmpty(aimMac) && !IsConnected && CheckIfBluetoothIsOn())
|
||||
{
|
||||
StartScan(10);
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ namespace Kill.Bluetooth
|
||||
|
||||
private IEnumerator StartUpgradeCoroutineInternal(BLEFrame frame, Action<bool> callback)
|
||||
{
|
||||
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR };
|
||||
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR, Data = new byte[0] };
|
||||
bool completed = false;
|
||||
|
||||
SendFrame(frame, (resp) =>
|
||||
@ -495,7 +495,7 @@ namespace Kill.Bluetooth
|
||||
private IEnumerator SendFrameCoroutine(BLEFrame frame, Action<BLEResponse> callback)
|
||||
{
|
||||
bool completed = false;
|
||||
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR };
|
||||
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR, Data = new byte[0] };
|
||||
|
||||
SendFrame(frame, (resp) =>
|
||||
{
|
||||
|
||||
@ -494,6 +494,8 @@ namespace Kill.Bluetooth.Protocol
|
||||
public static BLEResponse FromFrame(BLEFrame frame)
|
||||
{
|
||||
var response = new BLEResponse();
|
||||
// 无载荷的响应(如写ACK)也保证 Data 非空,避免回调中 BitConverter.ToString(null) 崩溃
|
||||
response.Data = new byte[0];
|
||||
if (frame.Data != null && frame.Data.Length > 0)
|
||||
{
|
||||
response.Status = frame.Data[0];
|
||||
|
||||
@ -389,6 +389,7 @@ namespace Kill.UI.Pages
|
||||
if(bluetoothDeviceInfoCoroutine!=null)
|
||||
{
|
||||
StopCoroutine(bluetoothDeviceInfoCoroutine);
|
||||
bluetoothDeviceInfoCoroutine = null;
|
||||
}
|
||||
// 设备断开重新加载主页(保持原行为,当前在主页也会重新加载)
|
||||
// 但切换设备(ChangeAimMac)导致的断开不重新加载,避免主页被销毁重建导致并发初始化
|
||||
@ -1004,6 +1005,24 @@ namespace Kill.UI.Pages
|
||||
}
|
||||
|
||||
public async Task Init()
|
||||
{
|
||||
// Init 在 async 链中抛异常会被静默吞掉:LoadingUI 引用计数无法归零(表现为卡 loading),
|
||||
// 且页面状态刷新(UpdateDeviceState)不会执行。这里统一兜底:记录完整异常并保证 Loading 收尾。
|
||||
try
|
||||
{
|
||||
await InitInternal();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[HomePageCtrl] Init 异常: {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
LoadingUI.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitInternal()
|
||||
{
|
||||
|
||||
if (DataManager.Instance.userInfo.device_count == 0 || (OwnedDevices.Count == 0 && SharedDevices.Count == 0))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user