Android平板如何正确检测QR扫描设备的连接与断开?
解决QR扫描设备(如BC-NL3000UⅡ)的USB插拔检测问题
你的代码能检测普通USB设备,但对这类QR扫描设备失效,核心原因是多数扫码器会被系统识别为HID键盘类设备,这类设备的插拔事件不会触发标准的UsbManager.ACTION_USB_DEVICE_ATTACHED/DETACHED广播,USB_STATE广播也无法精准捕捉。以下是针对性的解决方法:
方法1:监听InputDevice的插拔事件
因为扫码器模拟键盘输入,属于输入设备范畴,可通过监听InputDevice相关广播来检测:
步骤1:注册广播接收器
注册监听输入设备的添加/移除广播:
val inputDeviceReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent ?: return when (intent.action) { "android.hardware.input.action.INPUT_DEVICE_ADDED" -> { val deviceId = intent.getIntExtra("android.hardware.input.extra.DEVICE_ID", -1) if (deviceId != -1) { val device = InputDevice.getDevice(deviceId) if (isQrScanner(device)) { sendEventToFlutter("onUsbConnected") } } } "android.hardware.input.action.INPUT_DEVICE_REMOVED" -> { val deviceId = intent.getIntExtra("android.hardware.input.extra.DEVICE_ID", -1) if (isTargetScannerId(deviceId)) { sendEventToFlutter("onUsbDisconnected") } } } } } // 在Activity/Fragment的onCreate中注册,onDestroy中注销 val filter = IntentFilter().apply { addAction("android.hardware.input.action.INPUT_DEVICE_ADDED") addAction("android.hardware.input.action.INPUT_DEVICE_REMOVED") } context.registerReceiver(inputDeviceReceiver, filter)
步骤2:筛选目标扫码设备
实现设备匹配逻辑,通过名称或VID/PID定位目标扫码器:
private fun isQrScanner(device: InputDevice): Boolean { // 可通过adb命令`adb shell dumpsys input`获取设备的名称、VID/PID return device.name.contains("BC-NL3000UⅡ") || (device.vendorId == 0xXXXX && device.productId == 0xXXXX) } // 维护已连接的目标设备ID,用于断开时匹配 private var connectedScannerId = -1 private fun isTargetScannerId(deviceId: Int): Boolean { return deviceId == connectedScannerId }
方法2:主动枚举USB设备(兜底方案)
如果广播监听不稳定,可定时枚举USB设备,对比列表变化判断插拔:
private var lastDeviceList: List<UsbDevice> = emptyList() // 每2秒执行一次设备枚举 val timer = Timer().scheduleAtFixedRate(object : TimerTask() { override fun run() { val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager val currentDevices = usbManager.deviceList.values.toList() val addedDevices = currentDevices.filter { !lastDeviceList.contains(it) } val removedDevices = lastDeviceList.filter { !currentDevices.contains(it) } addedDevices.forEach { device -> if (isQrScannerUsb(device)) { sendEventToFlutter("onUsbConnected") } } removedDevices.forEach { device -> if (isQrScannerUsb(device)) { sendEventToFlutter("onUsbDisconnected") } } lastDeviceList = currentDevices } }, 0, 2000) private fun isQrScannerUsb(device: UsbDevice): Boolean { return device.vendorId == 0xXXXX && device.productId == 0xXXXX }
补充注意事项
- 确保APP拥有
android.permission.USB_PERMISSION权限,可在Manifest中声明:<uses-permission android:name="android.permission.USB_PERMISSION" /> - 部分扫码器支持切换工作模式(如从HID模式切换到USB串口模式),切换后可通过标准USB广播检测,同时需要串口通信库配合。
内容的提问来源于stack exchange,提问作者Tuan Pham Cong
相关产品推荐
相关产品推荐

