如何使用Android BLE ScanFilter通过UUID筛选蓝牙打印机?
问题原因分析
你遇到的核心问题是BLE扫描过滤器无法过滤经典蓝牙服务UUID:
- 你目标的UUID
00001101-0000-1000-8000-00805f9b34fb是经典蓝牙的串口服务(SPP)UUID,属于BR/EDR协议范畴,并非BLE GATT服务UUID。 - BLE扫描过滤器
ScanFilter的setServiceUuid是基于BLE设备广播包中携带的GATT服务UUID进行过滤的,经典蓝牙设备不会在BLE广播中携带SPP的UUID,因此过滤条件永远不匹配,onScanResult无回调。 fetchUuidsWithSdp()是经典蓝牙的API,用于查询设备的SDP服务记录,这也是你能通过它拿到目标UUID的原因,但这个操作和BLE扫描过滤是完全独立的流程。
解决方案
放弃使用BLE扫描过滤器,改为扫描所有设备后,通过SDP查询验证目标UUID:
1. 修改扫描逻辑,移除过滤器
启动扫描时不要传入ScanFilter,先获取所有可扫描到的设备:
val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).build() handler.postDelayed({ bluetoothAdapter.bluetoothLeScanner.stopScan(bleCallback) }, 15000) bluetoothAdapter.bluetoothLeScanner.startScan(null, settings, bleCallback)
2. 通过广播接收SDP查询结果
fetchUuidsWithSdp()是异步操作,需要注册广播接收器来接收查询完成的回调:
// 在Activity/Fragment中注册广播接收器 private val uuidReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val device = intent?.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) val uuids = intent?.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID)?.map { it as ParcelUuid } uuids?.forEach { parcelUuid -> if (parcelUuid.uuid.toString() == "00001101-0000-1000-8000-00805f9b34fb") { // 找到目标蓝牙打印机 Log.i(TAG, "找到目标设备: ${device?.name}") // 这里可以停止扫描或进行后续操作 bluetoothAdapter.bluetoothLeScanner.stopScan(bleCallback) } } } } // 在onCreate中注册 registerReceiver(uuidReceiver, IntentFilter(BluetoothDevice.ACTION_UUID))
3. 修改ScanCallback触发SDP查询
在onScanResult中调用fetchUuidsWithSdp(),并避免重复查询同一设备:
object : ScanCallback() { @SuppressLint("MissingPermission") override fun onScanResult(callbackType: Int, result: ScanResult?) { result?.device?.let { device -> // 避免重复查询同一设备,维护一个已查询设备的集合 if (!queriedDevices.contains(device.address)) { queriedDevices.add(device.address) device.fetchUuidsWithSdp() } } } // 全局变量存储已查询的设备地址 private val queriedDevices = mutableSetOf<String>() }
4. 注销广播接收器(避免内存泄漏)
在onDestroy中注销接收器:
override fun onDestroy() { super.onDestroy() unregisterReceiver(uuidReceiver) }
补充说明
- 如果目标打印机仅支持经典蓝牙(不支持BLE),可以直接使用经典蓝牙的扫描API(
BluetoothAdapter.startDiscovery()),而非BLE扫描API,效率更高。 - 经典蓝牙扫描需要
BLUETOOTH_SCAN权限,Android 12及以上还需要ACCESS_FINE_LOCATION权限,确保权限申请齐全。
内容的提问来源于stack exchange,提问作者rik194
相关产品推荐
相关产品推荐

