在大多数情况下,您需要在与 USB 设备通信时使用所有这些类(只有在进行异步通信时才需要 <activity ...> ... <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> 6)。一般来说,您需要获取 <activity ...> ... <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> 1 才能检索所需的 <activity ...> ... <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> 2。当您有了设备后,需要找到相应的 <activity ...> ... <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> 3 和该接口的 <activity ...> ... <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> 4 以进行通信。获得正确的端点后,打开 <activity ...> ... <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> 5 以与 USB 设备通信。
Android 清单要求
下表介绍了您需要向应用的清单文件中添加哪些内容,才能使用 USB 主机 API:
- 由于并非所有 Android 设备都保证支持 USB 主机 API,因此请添加 <?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources> 5 元素来声明您的应用使用 <?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources> 6 功能。
- 将应用的最低 SDK 设置为 API 级别 12 或更高级别。USB 主机 API 在更早的 API 级别中不存在。
- 如果您希望应用接收有关连接的 USB 设备的通知,请为主 Activity 中的 <?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>
7 Intent 指定 <?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>
8 和 <?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>
9 元素对。 <?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>
9 元素指向外部 XML 资源文件,用于声明有关要检测的设备的标识信息。
在 XML 资源文件中,为要过滤的 USB 设备声明 val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 1 元素。下表介绍了 val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 1 的属性。一般来说,如果您想过滤某个特定设备,请使用供应商 ID 和产品 ID;如果您想过滤一组 USB 设备(例如大容量存储设备或数码相机),请使用类、子类和协议。您可以指定所有这些属性,也可以不指定任何属性。如果不指定任何属性,则会与每个 USB 设备进行匹配,因此只在应用需要时才这样做:
- val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 3
- val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 4
- val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 5
- val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 6
- val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 7(设备或接口)
将资源文件保存在 val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 8 目录中。资源文件名称(不含 .xml 扩展名)必须与您在 <?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources> 9 元素中指定的名称相同。下面的示例展示了 XML 资源文件的格式。
清单和资源文件示例
以下示例展示了示例清单及其相应的资源文件:
<manifest ...> <uses-feature android:name="android.hardware.usb.host" /> <uses-sdk android:minSdkVersion="12" /> ... <application> <activity ...> ... <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>在这种情况下,以下资源文件应保存在 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 0 中,并指定应过滤具有指定属性的所有 USB 设备:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>使用设备
当用户将 USB 设备连接到 Android 设备时,Android 系统可以确定您的应用是否对连接的设备感兴趣。如果是,您可以根据需要设置与该设备的通信。为此,您的应用必须执行以下操作:
- 发现连接的 USB 设备,具体方法是使用 Intent 过滤器在用户连接 USB 设备时接收通知,或者枚举已连接的 USB 设备。
- 请求用户授予连接到 USB 设备的权限(如果尚未获得权限)。
- 通过在适当的接口端点读取和写入数据来与 USB 设备通信。
发现设备
您的应用可以通过使用 Intent 过滤器在用户连接 USB 设备时接收通知,或者枚举已连接的 USB 设备来发现设备。如果您希望应用自动检测所需的设备,那么使用 Intent 过滤器就非常有用。如果您想获取所有连接的设备的列表,或者您的应用没有 Intent 过滤器,那么枚举连接的 USB 设备就非常有用。
使用 Intent 过滤器
要让您的应用发现特定的 USB 设备,您可以指定一个 Intent 过滤器,用于过滤 <?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources> 7 Intent。除了此 Intent 过滤器外,您还需要指定一个资源文件来指定 USB 设备的属性,例如产品 ID 和供应商 ID。当用户连接与您的设备过滤器匹配的设备时,系统会向其显示一个对话框,询问他们是否要启动您的应用。如果用户接受,您的应用会自动获得访问设备的权限,直到设备断开连接。
以下示例展示了如何声明 Intent 过滤器:
<activity ...> ... <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>以下示例展示了如何声明指定您感兴趣的 USB 设备的相应资源文件:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources>在您的 Activity 中,您可以通过以下方式从 Intent 获取代表所连接设备的 <activity ...> ... <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> 2:
Kotlin
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
Java
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
枚举设备
如果应用有兴趣在运行时检查当前连接的所有 USB 设备,则可以枚举总线上的设备。使用 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 3 方法获取连接的所有 USB 设备的哈希映射。如果要通过映射获取设备,哈希映射会由 USB 设备的名称进行键控。
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
...
val deviceList = manager.getDeviceList()
val device = deviceList.get("deviceName")
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");
如果需要,您还可以从哈希映射中获取迭代器,并逐个处理每个设备:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
..
val deviceList: HashMap<String, UsbDevice> = manager.deviceList
deviceList.values.forEach { device ->
//your code
}
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
//your code
}
获取与设备通信的权限
您的应用必须获得用户的许可,才能与 USB 设备通信。
注意:如果您的应用使用 Intent 过滤器来发现已连接的 USB 设备,则它会在用户允许应用处理 Intent 时自动获得权限。否则,您必须在应用中明确请求权限,然后才能连接到设备。
某些情况下可能需要明确请求权限,例如应用枚举已连接的 USB 设备,然后要与其中一个设备通信时。在尝试与设备通信之前,您必须先检查是否具有访问设备的权限。否则,如果用户拒绝授予访问设备的权限,您会收到运行时错误消息。
要明确获取权限,请先创建广播接收器。此接收器监听在您调用 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 4 时接收广播的 Intent。调用 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 4 会向用户显示一个对话框,请求连接到设备的权限。以下示例代码展示了如何创建广播接收器:
Kotlin
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
0Java
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
1
要注册广播接收器,请在您的 Activity 的 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 6 方法中添加以下命令:
Kotlin
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
2Java
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
3
要显示对话框以向用户请求连接到设备的权限,请调用 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 4 方法:
Kotlin
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
4Java
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
5
当用户在该对话框中作出回复时,您的广播接收器会收到包含 UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 8 extra 的 Intent,即表示回答的布尔值。在连接到设备之前,请检查此 extra 的值是否为 true。
与设备通信
与 USB 设备的通信可以是同步的,也可以是异步的。在这两种情况下,您都应该创建一个新线程来执行所有数据传输,这样就不会锁定界面线程。要正确设置与设备的通信,您需要获取要与之通信的设备的相应 <activity ...> ... <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> 3 和 <activity ...> ... <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> 4,并使用 <activity ...> ... <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> 5 在此端点发送请求。通常,您的代码应该执行以下操作: