为什么 iOS 应用扫描一两次后就无法发现 BLE 外设?
仅凭这段代码无法确定外设消失的根因,也没有足够证据认定是 iOS 缓存问题。代码中可以直接确认两处问题:扫描失败后没有恢复 isScanning,以及异常处理中误用了 console.err。建议先修复这两处,再通过日志确认后续扫描是否真正执行、是否收到开发板的发现回调。
先修复扫描状态管理
当前代码只有在 startScanning() 成功执行后的 .then() 中才会将 isScanning 设为 false。如果它返回的 Promise 被拒绝,.catch() 只会打印错误,扫描标志仍为 true。此后调用 toggleScan() 时,函数都会在这里直接返回:
if (isScanning) return;
这会导致界面上的扫描操作无法启动新扫描。要确认它是否是本次故障的原因,需要检查外设消失前是否出现过 SCAN ERROR。如果同一轮扫描仍不断发现其他设备,这个状态问题就不足以解释为什么只有 STM32 开发板消失。
代码中还有一处:
console.err(e)
应改为 console.error(e)。如果 stopScanning() 抛出异常,错误的日志调用可能再次抛错,使函数提前退出,同样也不会恢复 isScanning。
用 try/finally 统一恢复状态
下面的示例沿用原代码中的 API 和参数,并加入扫描过程日志。它按照原代码的假设,将 startScanning() 的 Promise 完成视为本轮扫描结束。这一点仍需结合实际安装的库版本确认。如果 Promise 只表示扫描启动成功,应按该版本提供的结束通知管理状态。
const bluetooth = new Bluetooth();
async function toggleScan() {
if (isScanning) {
console.log("SCAN SKIPPED: already scanning");
return;
}
// 在等待权限结果之前设置标志,避免重复点击并发进入。
isScanning = true;
try {
const allowed = await requestBluetoothPermissions();
if (!allowed) return;
devices = [];
try {
await bluetooth.stopScanning();
} catch (err) {
console.error("STOP SCAN ERROR:", err);
throw err;
}
await new Promise(resolve => setTimeout(resolve, 500));
console.log("SCAN START:", Date.now());
await bluetooth.startScanning({
seconds: 4,
avoidDuplicates: true,
onDiscovered: (device) => {
console.log("DISCOVERED:", device);
devices = [...devices, device];
}
});
console.log("SCAN COMPLETED:", devices.length);
} catch (err) {
console.error("SCAN ERROR:", err);
} finally {
isScanning = false;
}
}
这个示例在停止扫描失败时会结束本轮操作,以便保留清晰的错误路径。如果日志显示“没有正在进行的扫描”也会使该版本的 stopScanning() 拒绝,需要根据实际错误类型单独处理,不能忽略所有停止失败。
原有的 500 ms 等待可以暂时保留用于对照,但现有材料无法证明这个延迟是必需的,也无法证明它能解决问题。
根据日志区分故障发生在哪一层
建议连续执行几轮扫描,记录每轮的开始、结束、错误和全部 onDiscovered 输出,重点观察以下情况:
| 观察结果 | 下一步检查 |
|---|---|
后续没有 SCAN START,出现 SCAN SKIPPED | 扫描标志是否未恢复,是否存在重叠调用 |
出现 STOP SCAN ERROR 或 SCAN ERROR | 根据完整错误对象排查扫描生命周期或权限状态 |
DISCOVERED 中包含开发板,但菜单没有显示 | 检查列表过滤、渲染条件和列表项标识 |
| 同一轮能发现其他设备,唯独没有开发板 | 检查开发板广播状态,以及库对该外设的发现和重复设备处理 |
| 只有重启开发板后才能再次发现 | 检查固件是否在连接、断开或超时后恢复广播 |
每次开始扫描都会执行 devices = []。因此,如果这一轮没有再次收到开发板的发现回调,它就不会出现在新列表中。列表消失本身不能说明设备被系统永久缓存或屏蔽。
不要仅凭 avoidDuplicates 判断缓存原因
你已经试过 avoidDuplicates: false,没有明显改善,因此不能把关闭重复设备过滤当作已验证的修复方法。
还需要区分当前扫描期间对重复发现事件的处理,以及库内部是否保存了跨扫描的设备状态。这些行为取决于实际库版本和实现。现有材料没有提供版本或相关实现,无法确认是否存在跨扫描缓存,也不能直接断定是库的缺陷。
如果日志把问题定位到发现回调,可以记录实际依赖版本,检查对应实现中 avoidDuplicates 的处理位置,以及停止、重新开始扫描时是否重置相关状态。
用一致条件比较 ST BLE Toolbox 和自己的应用
ST BLE Toolbox 能发现并连接开发板,说明开发板至少在该测试时刻可以正常工作。这还不足以完全排除 iOS 侧行为、应用扫描参数或外设状态差异。
对照测试时,先让 ST BLE Toolbox 断开连接并停止扫描,再测试自己的应用。分别比较开发板刚启动时和连接后断开时的表现,确认固件是否在需要被发现时持续广播或重新开始广播。
也可以临时延长扫描窗口,排查 4 秒窗口是否容易漏掉广播。延长后如果表现改善,只能说明扫描时长可能有关,不能单凭这一点确定广播间隔或最终根因。
修复异常路径和扫描标志后,可以根据回调日志判断问题发生在扫描启动、设备发现还是界面展示阶段,再检查缓存或 STM32WB 广播逻辑。
备注:内容仅供参考。
