USB 主机概览

USB 主机概览

当您的 Android 设备处于 USB 主机模式时,它会充当 USB 主机,为总线供电,

并枚举连接的 USB 设备。Android 3.1 及更高版本支持 USB 主机模式。

API 概览

在开始前,请务必了解您需要使用的类。通过

下表介绍了 android.hardware.usb 软件包中的 USB 主机 API。

表 1. USB 主机 API

类

说明

UsbManager

您可以枚举连接的 USB 设备并与之通信。

UsbDevice

表示连接的 USB 设备,并包含用于访问其标识的方法

信息、接口和端点。

UsbInterface

表示 USB 设备的接口,用于定义

设备。设备可以具有一个或多个用于通信的接口。

UsbEndpoint

表示接口端点,是此接口的通信通道。一个

接口可以有一个或多个端点,并且通常具有用于

实现与设备的双向通信

UsbDeviceConnection

表示与设备的连接,可在端点上传输数据。此课程

允许您同步或异步来回发送数据。

UsbRequest

表示通过 UsbDeviceConnection 与设备通信的异步请求。

UsbConstants

定义与 Linux 的 linux/usb/ch9.h 中的定义对应的 USB 常量

内核版本。

在大多数情况下,您都需要使用所有这些类(仅在进行异步通信时才需要 UsbRequest)

在与 USB 设备通信时会用到。通常,您需要获取 UsbManager 来检索所需的 UsbDevice。

有了设备后,您需要查找相应的 UsbInterface 及其 UsbEndpoint

进行通信获得正确的端点后,打开 UsbDeviceConnection 以与 USB 设备通信。

Android 清单要求

以下列表介绍了您需要先向应用的清单文件中添加的内容,然后才能

使用 USB 主机 API:

由于并非所有 Android 设备都保证支持 USB 主机 API,

添加一个 元素,用于声明您的应用使用

android.hardware.usb.host 功能。

将应用的最低 SDK 设置为 API 级别 12 或更高级别。USB 主机 API 不支持

存在的一些限制

如果您希望自己的应用在连接 USB 设备时收到通知,请指定

和 元素对

android.hardware.usb.action.USB_DEVICE_ATTACHED intent。通过

元素指向声明

待检测设备的识别信息。

在 XML 资源文件中,为 USB 声明 元素

您要过滤的设备以下列表介绍了

。一般来说,如果您要过滤广告,请使用供应商 ID 和产品 ID

如果您想过滤出某个组,请使用类、子类和协议

大容量存储设备或数码相机等 USB 设备。您可以指定不指定任何一项

所有这些属性如果不指定任何属性,则会匹配每个 USB 设备,因此请仅这样做

如果您的应用需要它:

vendor-id

product-id

class

subclass

protocol(设备或接口)

将资源文件保存在 res/xml/ 目录中。资源文件名

(没有 .xml 扩展名)必须与您在

元素。XML 资源文件格式为

示例。

清单和资源文件示例

以下示例展示了一个清单及其相应的资源文件:

...

...

android:resource="@xml/device_filter" />

在本例中,应将以下资源文件保存在

res/xml/device_filter.xml 并指定具有指定

属性:

使用设备

当用户将 USB 设备连接到 Android 设备时,Android 系统可以确定

您的应用是否对已连接的设备感兴趣。如果是这样,您可以设置

与设备进行通信。为此,您的应用必须执行以下操作:

使用 intent 过滤器发现连接的 USB 设备,以便在用户时收到通知

连接 USB 设备,或枚举已连接的 USB 设备。

请求用户授予连接到 USB 设备的权限(如果尚未获得权限)。

通过在相应接口上读取和写入数据,与 USB 设备通信

端点。

发现设备

您的应用可以使用 Intent 过滤器发现 USB 设备,方法是:

用户连接设备,或枚举已连接的 USB 设备。使用

如果您希望应用自动检测

所需的设备如果您想获取所有 USB 设备的列表,

连接的设备,或者您的应用未针对某个 intent 进行过滤。

使用 Intent 过滤器

要让您的应用发现特定的 USB 设备,可以指定一个 intent 过滤器,

android.hardware.usb.action.USB_DEVICE_ATTACHED intent 的过滤器。以及

此 intent 过滤器,您需要指定一个资源文件来指定 USB 接口的属性

例如产品和供应商 ID。当用户连接与您的设备匹配的设备时

过滤器,系统将向其显示一个对话框,询问他们是否要启动您的应用。

如果用户接受,您的应用会自动获得访问设备的权限,直到

设备已断开连接。

以下示例展示了如何声明 Intent 过滤器:

...

android:resource="@xml/device_filter" />

以下示例展示了如何声明指定

您感兴趣的 USB 设备:

在您的 activity 中,您可以获取代表UsbDevice

从 intent 中加载连接的设备,如下所示:

Kotlin

val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

Java

UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

枚举设备

如果您的应用想要检查当前连接的所有 USB 设备

当应用运行时,它可以枚举总线上的设备。使用 getDeviceList() 方法获取所有

已连接的 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 deviceList = manager.getDeviceList();

UsbDevice device = deviceList.get("deviceName");

如果需要,您还可以从哈希映射中获取迭代器,并处理每台设备

按 1:

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager

..

val deviceList: HashMap = manager.deviceList

deviceList.values.forEach { device ->

// your code

}

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

...

HashMap deviceList = manager.getDeviceList();

Iterator deviceIterator = deviceList.values().iterator();

while(deviceIterator.hasNext()){

UsbDevice device = deviceIterator.next();

// your code

}

获取与设备通信的权限

您的应用必须先获得

用户。

注意:如果您的应用使用

intent 过滤器来发现已连接的 USB 设备,它会自动接收

权限。否则,您必须请求

权限。

在某些情况下,您可能需要明确请求权限,例如,

应用枚举已连接且想要与之通信的 USB 设备

一个。在尝试与设备通信之前,您必须先检查是否具有访问设备的权限。如果

否则,如果用户拒绝授予访问设备的权限,您会收到运行时错误消息。

要明确获取权限,请先创建一个广播接收器。此接收器监听

当您调用 requestPermission() 时获取广播的 intent。调用 requestPermission() 会显示一个对话框,用于

用户请求允许连接到设备。以下示例代码展示了如何

创建广播接收器:

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"

private val usbReceiver = object : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

if (ACTION_USB_PERMISSION == intent.action) {

synchronized(this) {

val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {

device?.apply {

// call method to set up device communication

}

} else {

Log.d(TAG, "permission denied for device $device")

}

}

}

}

}

Java

private static final String ACTION_USB_PERMISSION =

"com.android.example.USB_PERMISSION";

private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (ACTION_USB_PERMISSION.equals(action)) {

synchronized (this) {

UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {

if(device != null){

// call method to set up device communication

}

}

else {

Log.d(TAG, "permission denied for device " + device);

}

}

}

}

};

要注册广播接收器,请在 onCreate() 方法中添加以下代码

活动:

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"

...

val manager = getSystemService(Context.USB_SERVICE) as UsbManager

...

permissionIntent = PendingIntent.getBroadcast(this, 0,

Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE)

val filter = IntentFilter(ACTION_USB_PERMISSION)

registerReceiver(usbReceiver, filter)

Java

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

private static final String ACTION_USB_PERMISSION =

"com.android.example.USB_PERMISSION";

...

permissionIntent = PendingIntent.getBroadcast(this, 0,

new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);

IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);

registerReceiver(usbReceiver, filter);

要显示对话框以向用户请求连接到设备的权限,请调用 requestPermission() 方法:

Kotlin

lateinit var device: UsbDevice

...

usbManager.requestPermission(device, permissionIntent)

Java

UsbDevice device;

...

usbManager.requestPermission(device, permissionIntent);

当用户回复该对话框时,您的广播接收器会收到包含

EXTRA_PERMISSION_GRANTED extra,是一个布尔值

代表答案。在连接到

设备。

与设备通信

与 USB 设备的通信可以是同步的,也可以是异步的。无论是哪种情况

应创建一个新线程来执行所有数据传输,这样您就不会阻塞

界面线程。要正确设置与设备的通信,您需要获取相应的

UsbInterface和UsbEndpoint

您要通过 UsbDeviceConnection 在此端点进行通信并发送请求的设备。通常,您的代码应该执行以下操作:

检查 UsbDevice 对象的属性,例如产品 ID、

供应商 ID 或设备类别来确定您是否要

设备。

当您确定要与该设备通信时,

UsbInterface,以便与

该接口的相应 UsbEndpoint。接口可以有一个

通常具有用于双向访问的 输入和输出端点

通信。

找到正确的端点后,打开 UsbDeviceConnection

访问该端点

使用 bulkTransfer() 或 controlTransfer() 方法提供要在端点上传输的数据。您应该

在另一个线程中执行此步骤以防止阻塞主界面线程。有关

有关在 Android 中使用线程的信息,请参阅进程和

线程。

以下代码段是执行同步数据传输的一种简单方式。您的代码

应具有更多逻辑,以正确找到要进行通信的正确接口和端点

此外,还应在与主界面线程不同的线程中执行数据转移:

Kotlin

private lateinit var bytes: ByteArray

private val TIMEOUT = 0

private val forceClaim = true

...

device?.getInterface(0)?.also { intf ->

intf.getEndpoint(0)?.also { endpoint ->

usbManager.openDevice(device)?.apply {

claimInterface(intf, forceClaim)

bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread

}

}

}

Java

private Byte[] bytes;

private static int TIMEOUT = 0;

private boolean forceClaim = true;

...

UsbInterface intf = device.getInterface(0);

UsbEndpoint endpoint = intf.getEndpoint(0);

UsbDeviceConnection connection = usbManager.openDevice(device);

connection.claimInterface(intf, forceClaim);

connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread

如需异步发送数据,请使用 UsbRequest 类对异步请求执行 initialize 和 queue 操作,然后等待结果

与requestWait()共享。

终止与设备的通信

与设备通信完毕或设备断开连接后,请通过以下方式关闭 UsbInterface 和 UsbDeviceConnection:

调用 releaseInterface() 和

close()。如需监听分离事件,请执行以下操作:

创建如下所示的广播接收器:

Kotlin

var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

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

}

}

}

}

Java

BroadcastReceiver usbReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {

UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

if (device != null) {

// call your method that cleans up and closes communication with the device

}

}

}

};

在应用内(而不是清单中)创建广播接收器,即可

让应用仅在运行时处理断开连接事件。这样,分离事件

只会发送到当前正在运行的应用,而不会广播到所有应用。

相关推荐

LOL小炮欧米茄小队皮肤怎么样?(lol小炮欧米伽小队皮肤多少钱)
神武4电脑版十周年前瞻:技能提升资质可变,战神罗成焕新登场!
各种新兴移动支付的安全性对比
365bet体育滚球

各种新兴移动支付的安全性对比

07-08 👁️‍🗨️ 8055
LOL小炮欧米茄小队皮肤怎么样?(lol小炮欧米伽小队皮肤多少钱)
菜的成语
mobile.365-588

菜的成语

07-07 👁️‍🗨️ 6179
五笔怎么打
mobile.365-588

五笔怎么打

08-25 👁️‍🗨️ 2932
显示点的坐标的步骤
mobile.365-588

显示点的坐标的步骤

09-06 👁️‍🗨️ 9940
手机小视频制作app排行榜TOP10推荐
mobile.365-588

手机小视频制作app排行榜TOP10推荐

07-02 👁️‍🗨️ 6709
百年巨匠:央视精选的艺术大师们
365bet信誉怎么样

百年巨匠:央视精选的艺术大师们

09-09 👁️‍🗨️ 8088