You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CBCentralManagerScanOptionAllowDuplicatesKey设为false仍重复发现蓝牙设备原因及解决

CBCentralManager重复扫描到同一设备的原因与解决方案

核心原因

CBCentralManagerScanOptionAllowDuplicatesKey 设为 false 时,苹果系统仅会对广播数据无变化、且在系统扫描缓存有效期内的同一外设去重,出现重复回调通常是以下情况导致:

  • 外设广播数据动态变化:只要外设的广播包内容(包括设备名、服务UUID、厂商自定义数据、信号强度等任意字段)发生变更,系统会将其判定为新的扫描结果,再次触发回调。很多物联网外设会在广播包中携带动态数据(比如传感器实时数值、连接状态标记),就会频繁触发重复回调。
  • 扫描操作被重复调用:你当前的代码在 centralManagerDidUpdateState 回调中每次检测到蓝牙状态为开启就直接发起扫描,如果该方法被多次触发(比如蓝牙状态临时波动、应用前后台切换触发状态刷新),重复调用 scanForPeripherals 会清空系统之前的扫描缓存,已经扫描到的设备会被当做新结果再次回调。
  • 系统扫描策略限制:应用切后台后系统会修改扫描策略,或者蓝牙模块缓存被系统主动清理时,也会导致已经扫到的设备再次触发回调。

解决方案

  • 本地自行实现去重逻辑:这是最稳妥的兼容方案,无需依赖系统的去重策略。声明一个集合存储已经扫描到的外设唯一标识 identifier,每次 didDiscover 回调触发时先做判断,不存在于集合中再执行业务逻辑,示例代码如下:
// 全局声明去重缓存
var discoveredPeripheralIds = Set<UUID>()

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    // 已经扫描过的设备直接忽略
    guard !discoveredPeripheralIds.contains(peripheral.identifier) else {
        return
    }
    // 新设备加入缓存,执行业务逻辑
    discoveredPeripheralIds.insert(peripheral.identifier)
    // 后续处理逻辑...
}

// 重新扫描前记得清空缓存
func restartScan() {
    discoveredPeripheralIds.removeAll()
    centralManager.stopScan()
    centralManager.scanForPeripherals(withServices: nil, options: [
        CBCentralManagerScanOptionAllowDuplicatesKey: false
    ])
}
  • 优化扫描调用逻辑:新增扫描状态标记,避免重复发起扫描,调整后的扫描启动代码如下:
var isScanning = false

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    self.bluetoothStatus = (central.state == .poweredOn)
    if bluetoothStatus && !isScanning {
        isScanning = true
        // 扫描前清空旧缓存
        discoveredPeripheralIds.removeAll()
        centralManager.scanForPeripherals(withServices: nil, options: [
            CBCentralManagerScanOptionAllowDuplicatesKey: false
        ])
    }
}

// 扫描结束后重置标记
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    central.stopScan()
    isScanning = false
}
  • 不需要持续扫描时及时调用 stopScan() 停止扫描,从根源避免多余回调。

内容的提问来源于stack exchange,提问作者Conrad Scherb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 18:45:02