优化蓝牙连接
This commit is contained in:
parent
fb67d4b324
commit
655afe81f3
@ -1006,7 +1006,7 @@
|
||||
},
|
||||
{
|
||||
"key": "100202",
|
||||
"zh": "修改密码",
|
||||
"zh": "请输入用户ID",
|
||||
"en": "Please enter User ID"
|
||||
},
|
||||
{
|
||||
@ -1017,7 +1017,7 @@
|
||||
{
|
||||
"key": "100204",
|
||||
"zh": "请输入要共享的用户ID",
|
||||
"en": "Enter shared user ID"
|
||||
"en": "Please Enter shared user ID"
|
||||
},
|
||||
{
|
||||
"key": "100205",
|
||||
|
||||
@ -969,6 +969,7 @@ GameObject:
|
||||
- component: {fileID: 1519237044948379669}
|
||||
- component: {fileID: 4142448484629704935}
|
||||
- component: {fileID: 4921898416580924308}
|
||||
- component: {fileID: 1825025902833908675}
|
||||
m_Layer: 5
|
||||
m_Name: Text (Legacy) (1)
|
||||
m_TagString: Untagged
|
||||
@ -1036,7 +1037,20 @@ MonoBehaviour:
|
||||
m_HorizontalOverflow: 1
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Please enter User ID
|
||||
m_Text: Enter shared user ID
|
||||
--- !u!114 &1825025902833908675
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5444693722322422585}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 89f1d49b50a31514787b4e268b1c73bb, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
textKey: 100204
|
||||
--- !u!1 &5524717387086965381
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@ -3517,7 +3517,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 345, y: -564}
|
||||
m_AnchoredPosition: {x: 345, y: -172}
|
||||
m_SizeDelta: {x: 690, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &854871756318895437
|
||||
@ -10811,7 +10811,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 345, y: -2408}
|
||||
m_AnchoredPosition: {x: 345, y: -466}
|
||||
m_SizeDelta: {x: 690, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &6739308067368723960
|
||||
@ -11868,7 +11868,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 345, y: -1918}
|
||||
m_AnchoredPosition: {x: 345, y: -368}
|
||||
m_SizeDelta: {x: 690, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &5027863063353656364
|
||||
@ -12732,7 +12732,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 345, y: -1286}
|
||||
m_AnchoredPosition: {x: 345, y: -270}
|
||||
m_SizeDelta: {x: 690, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &4389568299256833371
|
||||
|
||||
@ -3270,67 +3270,67 @@ PrefabInstance:
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
value: 590
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
value: 90
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
value: 295
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1507386632888176871, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
value: -312
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
value: 590
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
value: 45
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
value: 295
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4296973555611399213, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
value: -55
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4685927451915885120, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
value: 342
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5819498693055166909, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
@ -3340,7 +3340,7 @@ PrefabInstance:
|
||||
- target: {fileID: 5819498693055166909, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_IsActive
|
||||
value: 1
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6314676893636565267, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
@ -3450,32 +3450,32 @@ PrefabInstance:
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
value: 590
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
value: 42
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
value: 295
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6936886167337472632, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
value: -140
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7452104535586638788, guid: 52c284b3dc8d7b94297736ede9ad1f7e,
|
||||
type: 3}
|
||||
|
||||
@ -2,6 +2,7 @@ using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Kill.Core;
|
||||
using Kill.UI;
|
||||
using Kill.UI.Components;
|
||||
|
||||
namespace Kill.Bluetooth
|
||||
@ -89,12 +90,23 @@ namespace Kill.Bluetooth
|
||||
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
|
||||
{
|
||||
@ -106,9 +118,31 @@ namespace Kill.Bluetooth
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
OnDisconnected -= OnSelfDisconnected;
|
||||
if (_stateMonitorCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_stateMonitorCoroutine);
|
||||
_stateMonitorCoroutine = null;
|
||||
}
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 蓝牙断开后延迟跳回主页
|
||||
/// </summary>
|
||||
private void OnSelfDisconnected(string address)
|
||||
{
|
||||
IsConnected=false;
|
||||
// 延迟一下确保主页能读到最新的 IsConnected 状态
|
||||
StartCoroutine(DelayedGoHome());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator DelayedGoHome()
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
UIManager.Instance?.OpenMainPage(UIManager.PageName.homePage);
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
Initialize();
|
||||
@ -143,6 +177,20 @@ namespace Kill.Bluetooth
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经在等待蓝牙启用,跳过(不取消旧请求,避免重复弹窗)
|
||||
if (_enableBtCoroutine != null)
|
||||
{
|
||||
Log("已在等待用户启用蓝牙,跳过重复请求");
|
||||
return;
|
||||
}
|
||||
|
||||
// 用户已拒绝过蓝牙请求,不再自动弹出提示
|
||||
if (_userDeniedBluetooth)
|
||||
{
|
||||
Log("用户已拒绝蓝牙开启,跳过初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
Log("正在初始化蓝牙...");
|
||||
|
||||
// 先检查蓝牙是否开启,如果没有则尝试启用
|
||||
@ -153,6 +201,15 @@ namespace Kill.Bluetooth
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制初始化蓝牙(清除用户拒绝标记,用于用户主动触发)
|
||||
/// </summary>
|
||||
public void ForceInitialize()
|
||||
{
|
||||
_userDeniedBluetooth = false;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并启用蓝牙
|
||||
/// </summary>
|
||||
@ -165,6 +222,7 @@ namespace Kill.Bluetooth
|
||||
|
||||
if (bluetoothAdapter == null)
|
||||
{
|
||||
_enableBtCoroutine = null;
|
||||
OnError?.Invoke("设备不支持蓝牙");
|
||||
OnInitialized?.Invoke(false);
|
||||
return;
|
||||
@ -174,22 +232,16 @@ namespace Kill.Bluetooth
|
||||
|
||||
if (!isEnabled)
|
||||
{
|
||||
Log("蓝牙未开启,尝试启用...");
|
||||
|
||||
// 尝试静默启用蓝牙
|
||||
bool enableSuccess = bluetoothAdapter.Call<bool>("enable");
|
||||
|
||||
if (enableSuccess)
|
||||
Log("蓝牙未开启,使用 Intent 请求用户启用...");
|
||||
|
||||
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
||||
using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
|
||||
{
|
||||
Log("正在启用蓝牙,等待...");
|
||||
// 等待蓝牙启用
|
||||
StartCoroutine(WaitForBluetoothEnabled(onBluetoothReady));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 静默启用失败,请求用户启用
|
||||
RequestUserEnableBluetooth(onBluetoothReady);
|
||||
AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.bluetooth.adapter.action.REQUEST_ENABLE");
|
||||
currentActivity.Call("startActivityForResult", intent, 1);
|
||||
}
|
||||
|
||||
_enableBtCoroutine = StartCoroutine(WaitForBluetoothEnabled(onBluetoothReady));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -206,6 +258,65 @@ namespace Kill.Bluetooth
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 轮询等待蓝牙启用(Intent 之后,最长10秒)
|
||||
/// </summary>
|
||||
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<AndroidJavaObject>("getDefaultAdapter");
|
||||
if (adapter != null)
|
||||
{
|
||||
bool btOn = adapter.Call<bool>("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();
|
||||
@ -231,23 +342,23 @@ namespace Kill.Bluetooth
|
||||
// 4 = PoweredOff (蓝牙关闭)
|
||||
else if (state == 4)
|
||||
{
|
||||
Log("iOS 蓝牙未开启,提示用户");
|
||||
// iOS 不能自动打开蓝牙,只能提示用户去设置中开启
|
||||
Log("iOS 蓝牙未开启,跳转到系统设置...");
|
||||
ShowIOSTurnOnBluetoothPrompt();
|
||||
OnError?.Invoke("请在系统设置中开启蓝牙");
|
||||
OnInitialized?.Invoke(false);
|
||||
// 等待用户从设置返回(检测焦点变化 + 轮询蓝牙状态)
|
||||
_enableBtCoroutine = StartCoroutine(WaitForIOSBluetoothEnabled(onBluetoothReady));
|
||||
}
|
||||
// 3 = Unauthorized (未授权)
|
||||
else if (state == 3)
|
||||
{
|
||||
Log("iOS 蓝牙未授权");
|
||||
OnError?.Invoke("请在设置中允许使用蓝牙");
|
||||
OnInitialized?.Invoke(false);
|
||||
Log("iOS 蓝牙未授权,跳转到系统设置...");
|
||||
ShowIOSTurnOnBluetoothPrompt();
|
||||
_enableBtCoroutine = StartCoroutine(WaitForIOSBluetoothEnabled(onBluetoothReady));
|
||||
}
|
||||
// 2 = Unsupported (不支持蓝牙)
|
||||
else if (state == 2)
|
||||
{
|
||||
Log("设备不支持蓝牙");
|
||||
_enableBtCoroutine = null;
|
||||
OnError?.Invoke("设备不支持蓝牙");
|
||||
OnInitialized?.Invoke(false);
|
||||
}
|
||||
@ -259,96 +370,142 @@ namespace Kill.Bluetooth
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// iOS: 等待用户从设置返回并开启蓝牙(检测焦点 + 轮询)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示 iOS 开启蓝牙提示
|
||||
/// </summary>
|
||||
private void ShowIOSTurnOnBluetoothPrompt()
|
||||
{
|
||||
// 可以在这里显示一个弹窗,引导用户去设置
|
||||
// 或者使用原生插件跳转到设置页面
|
||||
OpenBluetoothSettingsIOS();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 监控蓝牙开关状态变化(App运行时)
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跨平台检查蓝牙是否开启
|
||||
/// </summary>
|
||||
private bool CheckIfBluetoothIsOn()
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 等待蓝牙启用
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator WaitForBluetoothEnabled(System.Action onBluetoothReady)
|
||||
{
|
||||
float timeout = 5f;
|
||||
float timer = 0f;
|
||||
|
||||
while (timer < timeout)
|
||||
try
|
||||
{
|
||||
using (AndroidJavaClass bluetoothAdapterClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter"))
|
||||
using (AndroidJavaClass btClass = new AndroidJavaClass("android.bluetooth.BluetoothAdapter"))
|
||||
{
|
||||
AndroidJavaObject bluetoothAdapter = bluetoothAdapterClass.CallStatic<AndroidJavaObject>("getDefaultAdapter");
|
||||
if (bluetoothAdapter != null && bluetoothAdapter.Call<bool>("isEnabled"))
|
||||
{
|
||||
Log("蓝牙已成功启用");
|
||||
onBluetoothReady?.Invoke();
|
||||
yield break;
|
||||
}
|
||||
AndroidJavaObject adapter = btClass.CallStatic<AndroidJavaObject>("getDefaultAdapter");
|
||||
if (adapter != null)
|
||||
return adapter.Call<bool>("isEnabled");
|
||||
}
|
||||
|
||||
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"))
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.bluetooth.adapter.action.REQUEST_ENABLE");
|
||||
currentActivity.Call("startActivityForResult", intent, 1);
|
||||
Log($"检查蓝牙状态异常: {ex.Message}");
|
||||
}
|
||||
|
||||
// 等待用户响应
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
#elif UNITY_IOS && !UNITY_EDITOR
|
||||
return GetBluetoothStateIOS() == 5;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行蓝牙初始化
|
||||
@ -365,8 +522,27 @@ namespace Kill.Bluetooth
|
||||
{
|
||||
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) =>
|
||||
{
|
||||
@ -377,7 +553,26 @@ namespace Kill.Bluetooth
|
||||
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)
|
||||
@ -388,6 +583,7 @@ namespace Kill.Bluetooth
|
||||
else
|
||||
{
|
||||
Log($"蓝牙初始化失败: {error}");
|
||||
_enableBtCoroutine = null;
|
||||
OnError?.Invoke($"初始化失败: {error}");
|
||||
OnInitialized?.Invoke(false);
|
||||
}
|
||||
@ -448,6 +644,15 @@ namespace Kill.Bluetooth
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化完成后延迟连接设备
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator DelayedConnectAfterInit(string address)
|
||||
{
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
Connect(address);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -460,10 +665,21 @@ namespace Kill.Bluetooth
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
OnError?.Invoke("蓝牙未初始化,请先调用Initialize()");
|
||||
Log("蓝牙未初始化,自动触发初始化流程...");
|
||||
_pendingStartScan = true;
|
||||
_pendingScanTimeout = timeout;
|
||||
Initialize();
|
||||
return;
|
||||
}
|
||||
|
||||
DoStartScan(timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实际执行扫描逻辑
|
||||
/// </summary>
|
||||
private void DoStartScan(float timeout)
|
||||
{
|
||||
if (IsScanning)
|
||||
{
|
||||
Log("已经在扫描中,先停止当前扫描...");
|
||||
@ -546,7 +762,11 @@ namespace Kill.Bluetooth
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
OnError?.Invoke("蓝牙未初始化");
|
||||
Log("蓝牙未初始化,自动触发初始化流程...");
|
||||
_pendingStartScan = true;
|
||||
_pendingScanTimeout = 999f;
|
||||
_pendingConnectAddress = deviceAddress;
|
||||
Initialize();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -156,8 +156,7 @@ namespace Kill.Network
|
||||
}
|
||||
else
|
||||
{
|
||||
// 自动显示错误提示
|
||||
ShowErrorTip(code.ToString());
|
||||
ToastUI.ShowText(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ public class ConnectDevicePageCtrl : MonoBehaviour
|
||||
|
||||
if (string.IsNullOrEmpty(ssid))
|
||||
{
|
||||
ToastUI.ShowText(LanguageManager.Instance.GetLanguage("100082") ?? "请输入WiFi名称");
|
||||
ToastUI.Show("100082");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ public class ConnectDevicePageCtrl : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
ToastUI.ShowText(LanguageManager.Instance.GetLanguage("100083") ?? "WiFi配置失败");
|
||||
ToastUI.Show("100083");;
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -353,6 +353,8 @@ public class ConnectDevicePageCtrl : MonoBehaviour
|
||||
deviceObjects.Clear();
|
||||
}
|
||||
deviceObjects = new List<GameObject>();
|
||||
// 用户进入配网页面,强制初始化以触发蓝牙开启提示
|
||||
BluetoothManager.Instance.ForceInitialize();
|
||||
BluetoothManager.Instance.StartScan(999f); // 扫描999秒
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,18 +127,18 @@ namespace Kill.UI.Pages
|
||||
switch (nowChartIndex)
|
||||
{
|
||||
case 0:
|
||||
startTime = now.AddDays(-1).ToString("yyyy-MM-dd");
|
||||
startTime = now.AddDays(-1).ToString("yyyy-MM-dd 00:00:00");
|
||||
break;
|
||||
case 1:
|
||||
startTime = now.AddDays(-((int)now.DayOfWeek + 1)).ToString("yyyy-MM-dd");
|
||||
startTime = now.AddDays(-((int)now.DayOfWeek + 1)).ToString("yyyy-MM-dd 00:00:00");
|
||||
|
||||
break;
|
||||
case 2:
|
||||
startTime = new DateTime(now.Year, now.Month, 1).ToString("yyyy-MM-dd");
|
||||
startTime = new DateTime(now.Year, now.Month, 1).ToString("yyyy-MM-dd 00:00:00");
|
||||
|
||||
break;
|
||||
case 3:
|
||||
startTime = new DateTime(now.Year, 1, 1).ToString("yyyy-MM-dd");
|
||||
startTime = new DateTime(now.Year, 1, 1).ToString("yyyy-MM-dd 00:00:00");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -328,7 +328,7 @@ namespace Kill.UI.Pages
|
||||
isQueryingStatus = false;
|
||||
statusQueryQueue?.Clear();
|
||||
UIManager.Instance?.ClearBackAction();
|
||||
UIManager.Instance.OpenPage(UIManager.PageName.homePage, null, true);
|
||||
// OpenPage 已移至 BluetoothManager.OnSelfDisconnected(全局监听 + 延迟)
|
||||
if(bluetoothDeviceInfoCoroutine!=null)
|
||||
{
|
||||
StopCoroutine(bluetoothDeviceInfoCoroutine);
|
||||
|
||||
@ -26,7 +26,6 @@ namespace Kill.UI.Pages
|
||||
{
|
||||
this.isBluetooth = isBluetooth;
|
||||
bluetoothStateIcon.color = stateBgColor[isBluetooth ? 1 : 0];
|
||||
bluetoothSearchIcon.SetActive(!isBluetooth);
|
||||
wifiStateIcon.color = stateBgColor[isWifi ? 1 : 0];
|
||||
bool isOnline = isBluetooth || isWifi;
|
||||
onlineStateIcon.sprite = onlineState[isOnline ? 1 : 0];
|
||||
@ -44,9 +43,16 @@ namespace Kill.UI.Pages
|
||||
}
|
||||
public void ClickScan()
|
||||
{
|
||||
if(!BluetoothManager.Instance.IsConnected)
|
||||
if (!BluetoothManager.Instance.IsConnected)
|
||||
{
|
||||
// 用户主动点击,强制初始化以触发蓝牙开启提示
|
||||
BluetoothManager.Instance.ForceInitialize();
|
||||
BluetoothManager.Instance.StartScan(10);
|
||||
bluetoothSearchIcon.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user