ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

拆解Nearby Glasses Android扫描引擎:从BluetoothLeScanner到Kotlin协程的BLE完整实现

拆解Nearby Glasses Android扫描引擎:从BluetoothLeScanner到Kotlin协程的BLE完整实现 拆解Nearby Glasses Android扫描引擎从BluetoothLeScanner到Kotlin协程的BLE完整实现【免费下载链接】yj_nearbyglassesattempting to detect smart glasses nearby and warn you项目地址: https://gitcode.com/gh_mirrors/yj/yj_nearbyglasses开源项目 Nearby Glasses 通过 BLE低功耗蓝牙扫描引擎检测周边的智能眼镜并向你发出警告。本文带你拆解它的 Android 扫描引擎从BluetoothLeScanner的扫描参数、RSSI 信号阈值、Company ID 识别规则到 Kotlin 协程与StateFlow的状态管理一次看懂 BLE 扫描的完整实现并告诉你如何获取源码动手学习。一、工作原理靠BLE广播帧揪出智能眼镜BLE 设备的 MAC 地址是随机化的设备名也不稳定所以 Nearby Glasses 无法对着某个固定信标扫描。它采用的是一套启发式识别方案 广播头里的 Company ID每只 BLE 设备广播ADV 帧时都会在 Manufacturer Specific Data 中携带厂商的公司 ID如 Meta 的0x01AB、0x058E。这些编号由蓝牙技术联盟统一分配不可变且必须携带是最可靠的识别依据。设备名匹配配对过程中智能眼镜会广播产品名代码会匹配rayban、ray-ban、HeyCyan等关键词。主服务 UUID针对 HeyCyan 生态的眼镜还检测固定服务标识7905FFF0-B5CE-4E99-A40F-4B1E122D00D0。项目内置的厂商清单可以在 smart_glasses_identifiers.csv 中找到。官方 README 对原理有更完整的说明见 README.md 的 How? 章节。二、扫描引擎的三个核心文件整个 Android 扫描引擎由三个 Kotlin 文件构成职责清晰文件职责BluetoothScanner.kt核心扫描器封装BluetoothLeScanner过滤 RSSI、解析广播帧、判定是否智能眼镜BluetoothScanService.kt前台服务持有扫描器生命周期、管理通知冷却与 UI 监听器DetectionEvent.kt检测事件模型承载 Company ID 判定规则isSmartGlasses与事件数据UI 层则由 MainActivity.kt 负责绑定服务、注册监听器、把检测结果渲染进调试日志。三、BluetoothLeScanner低延迟扫描参数解析打开 BluetoothScanner.kt最关键的是一段扫描参数配置val scanSettings ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // 低延迟模式 .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE) .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT) .setReportDelay(0) // 实时上报不攒批 .build()每个参数的用意很直白SCAN_MODE_LOW_LATENCY牺牲一点电量换取最短响应时间——发现智能眼镜后需要立刻警告所以选低延迟而不是低功耗模式。setReportDelay(0)结果逐条实时回调不做系统级攒批。MATCH_MODE_AGGRESSIVE放宽匹配限制尽量把每一帧广播都送进回调由应用自己过滤。回调侧则实现了ScanCallbackL43-L60onScanResult处理单帧、onBatchScanResults兜底处理批量帧、onScanFailed时把状态位复位。四、判定规则Company ID、设备名与UUID三重过滤每一帧广播到达后processScanResultL136 起会做四步处理 RSSI 门槛信号强度低于阈值默认 -75 dBm约相当于室内 3–10 米直接丢弃。RSSI 是接收信号强度指标负值越接近 0 表示设备越近。提取身份信息从广播记录中取出设备名、Manufacturer Specific Data 里的 Company ID注意代码同时检查服务 UUID 列表和 Service Data 两个位置见 L209-L227。智能眼镜判定调用 DetectionEvent.isSmartGlasses命中以下任一条件即触发Meta0x01AB/0x058EEssilorLuxotticaRay-Ban 制造商0x0D53Snap Spectacles0x03C2Zhuhai Jieli0x05D6设备名含rayban/ray-ban/heycyan广播中出现主服务 UUID回调上报命中后封装成DetectionEvent通过构造函数注入的onDeviceDetected回调抛出。⚠️ 项目作者特别提醒Company ID 只代表厂商而非眼镜VR 头显等同厂产品会造成误报请谨慎对待警告。更多厂商识别数据参见 smart_glasses_identifiers.csv。五、Kotlin协程与StateFlow简洁的并发设计这套引擎在并发处理上刻意保持了小而美 ✅StateFlow暴露扫描状态BluetoothScanner.kt#L36-L37 中用MutableStateFlow(false)包裹_isScanning外部通过只读StateFlow订阅。UI 只需isScanning.value true就能同步按钮文案无需轮询。服务层协程作用域BluetoothScanService.kt#L23 创建CoroutineScope(SupervisorJob() Dispatchers.Main)服务销毁时统一cancel()L186-L192保证资源干净释放。回调 监听器模式BLE 回调是系统线程驱动的handleDetectionL155-L172负责通知冷却——两次警告间隔由cooldownMs控制默认 10 秒避免同一副眼镜刷屏MainActivity 侧的detectionListener再用runOnUiThread切回主线程刷新界面。可以看到Kotlin 协程在这里承担的是作用域与生命周期管理角色而高频的广播回调仍走轻量回调链——对这种事件流型场景这是比Channel更省心的选择。六、前台服务与权限让扫描在后台活下去Android 对后台蓝牙扫描限制严格Nearby Glasses 的对策BluetoothScanService.kt#L56-L83以前台服务运行扫描在 Android 12 上声明FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE类型权限随系统版本适配MainActivity.kt#L552-L573Android 12 申请BLUETOOTH_SCAN/BLUETOOTH_CONNECT旧版本回退到定位权限Android 13 追加POST_NOTIFICATIONS。用户可在设置页关闭前台服务省电模式RSSI 阈值、通知冷却、调试日志行数等均可自定义七、获取源码动手跑一遍扫描引擎项目是纯 Kotlin Gradle 构建compileSdk 36minSdk 26克隆仓库即可本地构建git clone https://gitcode.com/gh_mirrors/yj/yj_nearbyglasses cd yj_nearbyglasses/Android ./gradlew assembleDebug建议的阅读顺序先读BluetoothScanner.kt的processScanResult主线再看DetectionEvent.isSmartGlasses的判定表最后回到BluetoothScanService理清服务与 UI 的通信方式。隐私政策与数据说明可见 PRIVACY.md。八、关键要点速览识别靠广播不靠连接Company ID 设备名 UUID 三重启发式零连接开销但有误报可能低延迟扫描模式SCAN_MODE_LOW_LATENCYreportDelay0为即时警告服务StateFlow管状态isScanning一个属性流打通 Service 与 UI前台服务保活Android 后台 BLE 扫描的标准姿势权限按版本分级Android 12 前后两套权限清单平滑兼容【免费下载链接】yj_nearbyglassesattempting to detect smart glasses nearby and warn you项目地址: https://gitcode.com/gh_mirrors/yj/yj_nearbyglasses创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进