Android CompanionDeviceManager按服务过滤时associate()无法发现设备
我正在使用Android的CompanionDeviceManager API查找附近支持心率测量的Bluetooth LE设备。代码如下:
final BluetoothLeDeviceFilter DEVICE_FILTER = new BluetoothLeDeviceFilter.Builder() .setScanFilter( new ScanFilter.Builder() /* .setServiceUuid( ParcelUuid.fromString( "0000180D-0000-1000-8000-00805f9b34fb" ) */ .build() ).build(); final AssociationRequest PAIRING_REQ = new AssociationRequest.Builder() .addDeviceFilter( DEVICE_FILTER ) .setSingleDevice( false ) .build(); final CompanionDeviceManager DEV_MANAGER = (CompanionDeviceManager) getSystemService( Context.COMPANION_DEVICE_SERVICE ); DEV_MANAGER.associate( PAIRING_REQ, new CompanionDeviceManager.Callback() { @Override public void onDeviceFound(@NonNull IntentSender chooserLauncher) { try { startIntentSenderForResult( chooserLauncher, RCQ_SELECT_DEVICE, null, 0, 0, 0 ); } catch (IntentSender.SendIntentException e) { Log.e( LOG_TAG, "onAssociationPending: failed to send intent" ); } } @Override public void onFailure(CharSequence errorMessage) { Log.e( LOG_TAG, "[FAIL] " + errorMessage ); } }, null );
未启用服务过滤时,代码可正常弹出显示所有附近BLE设备的对话框,包含目标设备;但移除注释启用心率服务UUID(0000180D-0000-1000-8000-00805f9b34fb)过滤后,在Android 12设备上无任何界面反馈,连空设备列表对话框都不出现,即使等待数小时也无变化。预期是显示扫描状态对话框或提示,超时后提示未找到符合过滤条件的设备,怀疑API调用存在错误,寻求解决方案。已知有未解决的同类问题。
针对Android 12上CompanionDeviceManager启用心率服务过滤无反馈的问题,可尝试以下修复方案:
1. 完善扫描过滤的UUID匹配模式
仅设置setServiceUuid可能因设备广播格式问题导致过滤失效,需添加部分匹配模式:
.setServiceUuid( ParcelUuid.fromString("0000180D-0000-1000-8000-00805f9b34fb"), BluetoothDevice.SCAN_FILTER_UUID_PARTIAL_MATCH )
该模式允许匹配广播中包含的部分UUID,兼容更多设备的广播格式。
2. 配置扫描超时
默认扫描无明确超时,需在AssociationRequest中设置超时时长,超时后会触发onFailure回调:
final AssociationRequest PAIRING_REQ = new AssociationRequest.Builder() .addDeviceFilter(DEVICE_FILTER) .setSingleDevice(false) .setTimeoutSeconds(30) // 设置30秒扫描超时 .build();
可在onFailure中添加用户提示,告知未找到设备。
3. 确认权限配置
Android 12及以上版本,BLE扫描需BLUETOOTH_SCAN权限,且需在Manifest中声明权限用途:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
若应用需通过BLE获取位置,需将neverForLocation替换为forLocation,同时确保已动态申请ACCESS_FINE_LOCATION权限。
4. 验证目标设备的广播数据
部分心率设备不会主动广播180D服务UUID,此时CompanionDeviceManager的过滤无法识别。可先用普通BLE扫描捕获设备广播:
BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner(); scanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids(); if (uuids != null) { for (ParcelUuid uuid : uuids) { Log.d("BLE_SCAN", "设备UUID: " + uuid.toString()); } } } });
若目标设备未广播该UUID,可补充设备名称过滤:
new ScanFilter.Builder() .setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805f9b34fb")) .setDeviceName("你的心率设备名称") .build()
5. 补充超时兜底逻辑
若onFailure未正常触发,可在启动扫描后手动设置定时器,超时后主动提示用户:
new Handler(Looper.getMainLooper()).postDelayed(() -> { Toast.makeText(this, "未找到符合条件的心率设备", Toast.LENGTH_SHORT).show(); }, 35000); // 比设置的超时多5秒,避免提前触发
内容的提问来源于stack exchange,提问作者Baltasarq

