You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android设备插入USB后UsbDevice始终返回null问题求助

解决UsbDevice始终返回null的问题

关键问题排查与修复

以下是导致你代码中UsbDevice始终为null的核心问题及对应修复方案:


1. Manifest中USB_DETACHED Action拼写错误

原代码中USB_DEVICE_DETACHED的Action开头多打了一个n,导致系统无法识别该广播:

<!-- 错误写法 -->
<action android:name="anandroid.hardware.usb.action.USB_DEVICE_DETACHED" />

<!-- 修正后 -->
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />

2. 自定义Action常量错误

你定义的ACTION_USB_ATTACHED和ACTION_USB_DETACHED值重复,且未使用系统标准Action,导致广播接收器无法正确响应设备连接/断开事件:

// 错误写法
private val ACTION_USB_DETACHED = "com.android.example.USB_DEVICE.DETACHED"
private val ACTION_USB_ATTACHED = "com.android.example.USB_DEVICE.DETACHED"

// 修正后:直接使用系统标准常量
private val ACTION_USB_ATTACHED = UsbManager.ACTION_USB_DEVICE_ATTACHED
private val ACTION_USB_DETACHED = UsbManager.ACTION_USB_DEVICE_DETACHED

3. 设备获取逻辑不完整

仅通过启动Intent获取设备的方式有局限性:当App不是被USB连接触发启动时,intent?.getParcelableExtra会返回null。需要主动遍历设备列表查找目标设备:

// 新增方法:遍历设备列表匹配目标设备
private fun findTargetDevice(): UsbDevice? {
    manager?.deviceList?.values?.forEach { usbDevice ->
        // 匹配device_filter中定义的vendorId和productId
        if (usbDevice.vendorId == 1234 && usbDevice.productId == 5678) {
            return usbDevice
        }
    }
    return null
}

// 在onCreate中调用:优先从Intent获取,失败则主动查找
device = intent?.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice()

4. 广播接收器未处理核心逻辑

原广播接收器对设备连接/断开事件、权限请求结果均无处理,导致无法更新设备实例或感知权限状态:

private val usbReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            ACTION_USB_ATTACHED -> {
                // 设备连接时重新获取实例并检查权限
                device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice()
                device?.let { checkAndRequestPermission(it) }
            }
            ACTION_USB_DETACHED -> {
                // 设备断开时清空实例
                device = null
                Toast.makeText(context, "USB设备已断开", Toast.LENGTH_SHORT).show()
            }
            ACTION_USB_PERMISSION -> {
                // 处理权限请求结果
                val usbDevice = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    usbDevice?.let {
                        device = it
                        Toast.makeText(context, "权限获取成功", Toast.LENGTH_SHORT).show()
                        // 此处可开始设备通信逻辑
                    }
                } else {
                    Toast.makeText(context, "权限获取失败", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
}

5. USB角色与连接场景误解

你提到将设备连接至电脑/充电器时返回null,这属于正常情况:

  • 连接电脑:此时Android设备是USB外设,电脑是主机,Android端无法获取自己的UsbDevice实例。
  • 连接充电器:充电器仅提供供电,无数据通信功能,不会被识别为USB设备。
  • 若要获取UsbDevice,需将Android设备作为USB主机,通过OTG线外接USB外设(如U盘、传感器等)。

完整修正后的代码

AndroidManifest.xml

<intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>

<intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>

<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
    android:resource="@xml/device_filter" />

device_filter.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
    private val ACTION_USB_ATTACHED = UsbManager.ACTION_USB_DEVICE_ATTACHED
    private val ACTION_USB_DETACHED = UsbManager.ACTION_USB_DEVICE_DETACHED

    private var filter: IntentFilter? = null
    private var manager: UsbManager? = null
    private var permissionIntent: PendingIntent? = null
    private var device: UsbDevice? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        manager = getSystemService(Context.USB_SERVICE) as UsbManager
        permissionIntent = PendingIntent.getBroadcast(
            this, 0, Intent(ACTION_USB_PERMISSION), 
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                PendingIntent.FLAG_IMMUTABLE
            } else {
                PendingIntent.FLAG_UPDATE_CURRENT
            }
        )

        // 初始化IntentFilter并注册广播接收器
        filter = IntentFilter().apply {
            addAction(ACTION_USB_ATTACHED)
            addAction(ACTION_USB_DETACHED)
            addAction(ACTION_USB_PERMISSION)
        }
        registerReceiver(usbReceiver, filter)

        // 获取设备实例
        device = intent?.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice()
        device?.let { checkAndRequestPermission(it) } ?: run {
            Toast.makeText(applicationContext, "未检测到目标USB设备", Toast.LENGTH_SHORT).show()
        }
    }

    // 查找目标USB设备
    private fun findTargetDevice(): UsbDevice? {
        manager?.deviceList?.values?.forEach { usbDevice ->
            if (usbDevice.vendorId == 1234 && usbDevice.productId == 5678) {
                return usbDevice
            }
        }
        return null
    }

    // 检查并请求权限
    private fun checkAndRequestPermission(device: UsbDevice) {
        if (!manager!!.hasPermission(device)) {
            manager?.requestPermission(device, permissionIntent)
        } else {
            Toast.makeText(applicationContext, "已获取设备权限", Toast.LENGTH_SHORT).show()
        }
    }

    private val usbReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                ACTION_USB_ATTACHED -> {
                    device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) ?: findTargetDevice()
                    device?.let { checkAndRequestPermission(it) }
                }
                ACTION_USB_DETACHED -> {
                    device = null
                    Toast.makeText(context, "USB设备已断开", Toast.LENGTH_SHORT).show()
                }
                ACTION_USB_PERMISSION -> {
                    val usbDevice = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        usbDevice?.let {
                            device = it
                            Toast.makeText(context, "权限获取成功", Toast.LENGTH_SHORT).show()
                        }
                    } else {
                        Toast.makeText(context, "权限获取失败", Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(usbReceiver)
    }
}

内容的提问来源于stack exchange,提问作者Ahmet Yılmaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 13:50:46