Android USB Host模式收发数据

AS Wi-Fi调试(Android12+)

在调试USB设备之后,唯一的Type-C接口就被占用了。这个时候有无线调试就可以解决。可以通过TCPIP连接调试,也可以使用Wi-Fi配对调试。下面讲解Wi-Fi调试的配置过程:

  1. Wi-Fi连接:电脑和手机笔记连接在同一个路由器
  2. 打开AS的Wi-Fi调试配对二维码
#Android Studio
Run Devices➡️ Pair devices over Wi-Fi➡️ Pair using QR code
使用Android Studio Wi-Fi调试
  1. 打开手机无线调试功能
#Android 12+手机
设置 ➡️ 其他/更多设置 ➡️ 开发者选项 ➡️ 调试-无线调试 ➡️ 开启 ➡️ 使用二维码配对设备

OTG模式

Oppo、Vivo

Oppo、Vivo想要调试USB设备,需要先打开OTG模式,否则手机无法识别外接USB设备。

设置 ➡️ 其他/更多设置 ➡️ OTG连接

华为、LG、Google等

大部分的厂商都是默认打开OTG的,可以直接插入USB设备访问

示例代码

Manifest配置

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.usb.demo">

    <uses-feature android:name="android.hardware.usb.host" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.UsbDemo"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </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" />
        </activity>
    </application>

</manifest>

Device Filter配置

资源文件保存在 res/xml/device_filter.xml 中,并指定应过滤具有指定属性的所有USB 设备

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <usb-device
        product-id="1234"
        vendor-id="5678" />
</resources>

监听USB设备添加/删除

使用BroadcastReceiver监听USB事件

    private val usbReceiver = object : BroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent) {
            if (ACTION_USB_PERMISSION == intent.action) {
                synchronized(this) {
                    Lg.i("Usb Action")
                    val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        device?.apply {
                            exchangeData(this)
                        }
                    } else {
                        Lg.i("permission denied for device ${device?.deviceName}")
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
                val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
                device?.apply {
                    // call your method that cleans up and closes communication with the device
                }
            }
        }
    }

监听设备

Android手机一般只有一个USB接口,只需要获取到device就执行监听即可。

    private fun enumerateDevices() {
        val manager = getSystemService(Context.USB_SERVICE) as UsbManager
        val deviceList = manager.deviceList
        Lg.i("usb devices count=${deviceList.size}, list: ${deviceList.values}")
        if (deviceList.size < 1) {
            Lg.e("没有USB设备")
            return
        }
        val filter = IntentFilter(ACTION_USB_PERMISSION)
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
        registerReceiver(usbReceiver, filter)

        device = deviceList.values.first()
        Lg.i("product Name= ${device.productName}")
        val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)
        manager.requestPermission(device, permissionIntent)
    }

收发数据

使用Endpoint发送数据,一般Endpoint是成对出现的,一收一发。

    private fun exchangeData(device: UsbDevice) {
        val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager

        //一般为1个USB口
        Lg.i("USB Interface count=${device.interfaceCount}")
        device.getInterface(0).also { usbInterface ->
            //一般为2个端点,一收一发
            Lg.i("endpointCount=${usbInterface.endpointCount}")
            usbManager.openDevice(device)?.apply {
                usbInterface.getEndpoint(1).also { endpoint ->
                    Lg.i("endpointNumber=${endpoint.endpointNumber}")
                    claimInterface(usbInterface, forceClaim)
                    val bytes = byteArrayOf(0x01, 0x02, 0x03, 0x04)
                    //发送数据
                    bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread
                }
                usbInterface.getEndpoint(0).also { endpoint ->
                    //创建buffer接收数据
                    val responses = ByteArray(size = 64)
                    bulkTransfer(endpoint, responses, responses.size, TIMEOUT)
                    Lg.i("responses= ${responses.toHex()}")
                }
            }
        }
    }

    fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }

例子中用到的Const

    companion object {
        private const val TIMEOUT = 30
        private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
    }

官方文档(中文)

《USB Host》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容