
Android低功耗蓝牙BLE完全指南用Android-Extensions BleScanner快速扫描与过滤设备【免费下载链接】Android-ExtensionsAn Android library with modules to quickly bootstrap an Android application.项目地址: https://gitcode.com/gh_mirrors/an/Android-ExtensionsAndroid-Extensions 是一个帮助快速搭建 Android 应用的开源库其communications模块内置了一套完整的低功耗蓝牙BLE扫描工具核心类BLEScanner负责扫描、ScanFilterCompat负责过滤几行代码即可实现「扫描 BLE 设备 → 过滤 → 拿到结构化结果」无需自己处理 Android 新旧两套 API 的兼容问题。 本文面向新手按照顺序读完即可掌握Android BLE 扫描与Android-Extensions BLE 扫描器的完整用法。一、为什么要用统一的 BLE 扫描入口Android 的蓝牙低功耗Bluetooth Low Energy扫描 API 历来有两套新 APIAPI 21BluetoothAdapter.getBluetoothLeScanner()ScanCallback支持扫描设置旧 APIAPI 21 以下BluetoothAdapter.startLeScan()LeScanCallback返回的是一串原始广播字节需要自己解析如果从零自写扫描器版本判断、广播数据解析、过滤器组装全要自己来。communications 模块把这些坑都包办好了你本要操心的事communications 模块的做法两套扫描 API 的兼容BLEScanner根据系统版本自动选择BLEScanner.java#L72-L83广播原始数据解析ScanRecordCompat自动从字节流解析出设备名、服务 UUID 等过滤条件ScanFilterCompat提供全版本统一的内存过滤结果模型ScanResultCompat统一封装设备、信号强度、时间戳 一个值得注意的细节即使在 API 21 上过滤器也是在matchesFilters()中于内存中逐条匹配BLEScanner.java#L85-L89所以过滤行为在各版本上表现一致。二、快速上手三步构建你的 BLE 扫描器入口是BLEScanner.getBuilder(adapter)返回的 BuilderBLEScanner.java#L63-L65最小可用写法如下val scanner BLEScanner.getBuilder(bluetoothAdapter) .withCallBack { result - Log.d(BLE, 发现设备: ${result.device.name}) } .build() scanner.startScan() // 扫描结束后记得调用 scanner.stopScan()三个要点回调必填——build()时若未设置回调会直接抛异常没有回调的扫描本来也无意义start/stop 成对出现——BLE 扫描是手机最耗电的操作之一用完务必停止先确认蓝牙可用——可用scanner.isEnabled()检查未开启时用BluetoothAdapter.ACTION_REQUEST_ENABLE引导用户打开开关三、BLE 扫描过滤器精准锁定目标设备在设备密集的环境里BLE 广播包会源源不断涌来。ScanFilterCompat支持按 5 个维度过滤Builder 入口见 ScanFilterCompat.java#L137-L139过滤维度设置方式典型场景设备名称setDeviceName(MyScale)按名字找设备MAC 地址setDeviceAddress(01:02:03:AB:CD:EF)重连已配对的设备服务 UUIDsetServiceUuid(ParcelUuid(...))找提供某服务的设备最常用服务数据setServiceData(uuid, data)按服务负载内容识别厂商数据setManufacturerData(id, data)按厂商标识识别 UUID 和数据类过滤还支持位掩码如setServiceUuid(uuid, uuidMask)掩码位为 1 表示该位必须匹配、为 0 表示忽略非常适合「UUID 只匹配前缀」的场景。匹配规则总结为一句话逻辑见 ScanFilterCompat.java#L292-L340同一个过滤器内的多个字段是「与」关系添加的多个过滤器之间是「或」关系。示例 App 默认用服务 UUID 过滤写法如下BleViewModel.kt#L100-L112BLEScanner.getBuilder(bluetoothManager.adapter) .addFilter(ScanFilterCompat.getBuilder() .setServiceUuid(ParcelUuid(UUID.fromString(CUSTOM_SERVICE_UUID))) .build()) .withCallBack { emitter.onNext(BleUpdate.Found(it)) } .build()四、读懂扫描结果ScanResultCompat 给了你什么每发现一个设备回调都会收到一个ScanResultCompat包含 4 个关键信息ScanResultCompat.java#L98-L125device远端BluetoothDevice可取名称与 MAC 地址scanRecord解析好的广播记录ScanRecordCompat设备名、服务 UUID 列表即取即用rssi信号强度dBm范围 -127127数值越大距离越近常用于排序和近场判断timestampNanos结果观测时间戳可用于去重与统计五、权限与兼容性清单扫描前的必做检查✅ 在扫描前依次确认以下事项。communications 模块的清单文件已声明了基础权限communications/src/main/AndroidManifest.xml#L4-L6BLUETOOTH / BLUETOOTH_ADMIN——蓝牙基础权限ACCESS_COARSE_LOCATION——Android 6.0 起 BLE 扫描需要粗略位置权限且必须运行时动态申请设备能力检查——并非所有手机都支持 BLE先查PackageManager.FEATURE_BLUETOOTH_LE蓝牙开关检查——adapter.isEnabled为 false 时引导用户开启示例 App 的权限处理流程值得直接借鉴onResume中先检查位置权限、再向 ViewModel 发出扫描指令若蓝牙未开启则自动跳转系统蓝牙开关页BleScanFragment.kt#L108-L127。⚠️ 提示如果你的项目 targetSdk 较高Android 11记得在应用清单中补充声明新版权限BLUETOOTH_SCAN/BLUETOOTH_CONNECT。六、示例 App 实战10 秒自动停止的定时扫描仓库的演示 App 内置了完整的 BLE 扫描页核心流程是进入页面即申请位置权限并自动开始扫描BleViewModel把扫描结果封装为响应式流按 MAC 地址去重、按名称排序10 秒后自动停止takeUntil(Flowable.timer(SCAN_PERIOD, ...))SCAN_PERIOD 10秒BleViewModel.kt#L114——这是省电的好习惯强烈建议照抄停止后列表展示全部发现的设备点击可查看设备地址示例 App 中的图片资源集中在app/src/main/res/drawable/目录与 BLE 扫描页共存于同一个演示应用中例如这张示例图片七、常见问题速查表现象原因与解决回调一直不触发蓝牙未开启、位置权限未授予或过滤条件写错UUID 拼写错误最常见扫描特别耗电长时间扫描未停止参考示例 App 的「定时扫描 自动 stop」列表出现重复设备同一设备会持续广播按device.address去重示例用distinctByscanRecord为空部分设备广播内容解析失败使用前请判空过滤器行为还有现成的仪器化测试可供参考ScanFilterCompatTest.java。八、总结本文以 Android-Extensions 的 BLE 扫描器为主线走完了 Android 蓝牙低功耗扫描的完整链路BLEScanner统一扫描入口新旧系统版本 API 兼容一步到位ScanFilterCompat5 个维度的过滤条件 位掩码部分匹配ScanResultCompat / ScanRecordCompat解析完毕、即取即用的扫描结果示例 App权限申请、定时扫描、结果去重的完整可参考实现四个核心类源码都位于 communications 模块的 bluetooth 包下建议配合 communications/README.md 一起阅读——其中还提供了一组 NSD 局域网服务发现工具与 BLE 扫描搭配使用非常适合物联网项目。【免费下载链接】Android-ExtensionsAn Android library with modules to quickly bootstrap an Android application.项目地址: https://gitcode.com/gh_mirrors/an/Android-Extensions创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考