Android 12(targetSdkVersion31)BLE自定义serviceUUID获取异常求助
Android 12 (targetSdk31) BLE Scan Response 获取问题解决
行为变更原因
Android 12(对应targetSdkVersion 31)调整了BLE扫描的默认行为——系统不再自动向BLE设备请求Scan Response包。此前targetSdkVersion 30及以下版本,系统会在扫描到广播包后自动触发Scan Response请求,因此你能直接从ScanRecord中获取到包含在Scan Response里的自定义Service UUID;但升级后这个默认行为被移除,仅当扫描时显式配置相关参数,才会主动请求Scan Response。
解决方法
1. 启用非传统扫描模式触发Scan Response请求
使用ScanSettings.Builder时添加setLegacy(false),启用非传统扫描模式。该模式下系统会主动请求Scan Response包,你就能在ScanResult中拿到完整的ScanRecord。
示例代码:
ScanSettings scanSettings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .setLegacy(false) // 关键配置,触发Scan Response请求 .build(); // 启动扫描(可先不设置过滤,后续手动校验) bluetoothLeScanner.startScan(null, scanSettings, scanCallback);
注:非传统扫描模式仅支持Android 8.0+,你的targetSdk31覆盖的系统版本均满足要求。
2. 手动触发Scan Response请求
如果上述方法不生效,可在扫描到设备后,调用BluetoothDevice.readRemoteRssi()触发设备发送Scan Response。该操作无需连接设备,触发后会在ScanCallback的onScanResult中返回包含完整Service UUID的ScanRecord。
3. 正确处理UUID过滤
因为目标Service UUID在Scan Response中,直接用ScanFilter按UUID过滤会失效(过滤仅基于广播包数据),需改为:
- 不设置
ScanFilter,先扫描所有BLE设备; - 在
ScanCallback的onScanResult中解析ScanRecord,手动校验是否包含目标自定义128位UUID。
解析示例代码:
private final ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); ScanRecord scanRecord = result.getScanRecord(); if (scanRecord == null) return; List<ParcelUuid> serviceUuids = scanRecord.getServiceUuids(); if (serviceUuids != null) { UUID targetUuid = UUID.fromString("你的自定义128位UUID"); for (ParcelUuid uuid : serviceUuids) { if (uuid.getUuid().equals(targetUuid)) { // 找到目标设备,执行后续逻辑 break; } } } } };
额外注意事项
- 权限配置:Android 12+需在Manifest中声明
BLUETOOTH_SCAN权限,若无需位置信息,需添加android:usesPermissionFlags="neverForLocation"避免请求位置权限; - 运行时权限:需在代码中主动请求
BLUETOOTH_SCAN权限,否则扫描会失败; - 设备验证:使用BLE调试工具(如nRF Connect)确认你的传感器确实在Scan Response中包含目标Service UUID,排除设备端问题。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

