fix(device): 修复配网页蓝牙搜索无法停止与网络配置按钮失效

与重构前 uni-app 版逐项对比定位三处回归:
- useDidHide 停搜索:旧版 onHide/onUnload 双触发,迁移版只有 useEffect
  卸载清理,navigateTo 进入配网页或切后台时组件不卸载,扫描持续空转
- prepareWifiConfig 加 60s 超时兜底:createBLEConnection 在部分机型
  失败后不回调,discoverServices/notify 无原生超时,loading 遮罩
  永不撤除导致按钮永久禁用
- 连接失败后安全断开(对齐旧版 safeDisconnect):清掉 OS 层残留连接,
  避免"已连接(10010)"卡死后续重试;并补回"设备已连接"成功提示
This commit is contained in:
ozh 2026-09-09 17:43:22 +08:00
parent 1baca70e35
commit 58d0ee8ad7
1 changed files with 35 additions and 3 deletions

View File

@ -1,20 +1,35 @@
import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import Taro, { useDidHide } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { Navbar } from '@/components/navbar'
import { useBle } from '@/ble/hooks/useBle'
import { navigateTo } from '@/utils/navigation'
import { ROUTES } from '@/constants/routes'
import { getErrorMessage } from '@/utils/error'
import { showToast } from '@/utils/toast'
import { DEVICE_ACTION_KEYS, ACTION_REGISTRY, isEp832Device } from '@/constants/deviceActions'
import type { BleDevice } from '@/ble/hooks/useBle'
import styles from './ble-config.module.scss'
// createBLEConnection 最多 3 次尝试(15s 超时 + 1.2s 重试间隔)约 47s,
// 兜底覆盖 discoverServices/notify 无原生超时的场景,保证 loading 遮罩必然撤除
const PREPARE_WIFI_TIMEOUT_MS = 60000
function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {
return Promise.race([
promise,
new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error(message)), ms)
})
])
}
export default function DeviceBleConfig() {
const { state, discovery } = useBle()
const [preparingId, setPreparingId] = useState('')
// 页面隐藏/卸载时清理搜索(对齐旧版 onHide/onUnload),连接保持供配网页使用
// 页面隐藏(navigateTo 配网页/切后台)与卸载(返回)时停搜索,连接保持供配网页使用。
// useEffect 的清理只在卸载触发,压栈后台时组件不卸载,必须补 useDidHide(对齐旧版 onHide/onUnload)
useEffect(() => {
return () => {
if (discovery.getState().isSearching) {
@ -24,6 +39,12 @@ export default function DeviceBleConfig() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useDidHide(() => {
if (discovery.getState().isSearching) {
discovery.stopSearch(false)
}
})
const startScan = async () => {
if (state.searching) {
await discovery.stopSearch()
@ -46,10 +67,19 @@ export default function DeviceBleConfig() {
let prepError: unknown = null
try {
await discovery.prepareWifiConfig(deviceId)
// createBLEConnection 部分机型失败后不回调(微信基础库缺陷),
// discoverServices/notify 也无原生超时;不设兜底会导致 loading 永不消失、按钮永久失效
await withTimeout(
discovery.prepareWifiConfig(deviceId),
PREPARE_WIFI_TIMEOUT_MS,
`连接设备超时(${PREPARE_WIFI_TIMEOUT_MS / 1000}s),请重试`
)
navigateTo(ROUTES.DEVICE_CONFIG)
} catch (error) {
prepError = error
// 对齐旧版 safeDisconnect:连接半途失败时清掉 OS 层残留连接,
// 否则后续重试会被"已连接(10010)"错误卡死
discovery.disconnectDevice().catch(() => {})
} finally {
setPreparingId('')
// showLoading 与 showToast 共用同一遮罩层,必须先 hideLoading 再弹提示
@ -64,6 +94,8 @@ export default function DeviceBleConfig() {
showCancel: false,
confirmText: '知道了'
})
} else {
showToast('设备已连接,请填写WiFi信息')
}
}