先附上 Android USB 官方文档
Android通过两种模式支持各种 USB 外设和 Android USB 附件(实现Android附件协议的硬件):USB附件和USB主机。USB开发需 Android 3.1(API级别12)以上。由于本人工作中只用到了主机模式,所以本文的侧重点在主机模式开发。
在使用 USB 连接设备调试的时候,USB 外设将不能连接至设备,可以使用 WIFI 的方式连接调试,settings -> plugin -> WiFi ADB 插件好几个,选个适合自己的就 OK。
或者…我这里正好有一篇Android 模拟器连接 USB 设备喜欢点个赞哈!
<uses-feature android:name="android.hardware.usb.host"/>
<activity
android:name=".MainActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<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>
<resources>
<usb-device
class="255"
product-id="5678"
protocol="1 "
subclass="66"
vendor-id="1234" />
resources>
配置好清单文件后当用户连接与您的设备过滤器匹配的设备时,系统会向他们显示一个对话框,询问他们是否要启动您的应用程序。如果用户接受,则应用程序将自动具有访问设备的权限,直到设备断开连接。如果给了默认,那么这个 USB 设备插入后会自动启动这个 Activity
在清单文件中配置好以后我们直接进入 Java 代码环节
Android 3.1(API级别12)以上原生提供了 USB 开发的 API,在android.hardware.usb包下提供了开发的相关类。
Class | 说明 |
---|---|
UsbManager | 获得 USB 管理器,与连接的 USB 设备通信。 |
UsbDevice | USB 设备的抽象,每个UsbDevice 都代表一个 USB 设备。 |
UsbInterface | 定义了设备的功能集,一个 UsbDevice 可能包含一个或多个UsbInterface,每个 Interface 都是独立的。 |
UsbEndpoint | UsbEndpoint 是 interface 的通信通道。 |
UsbDeviceConnection | host 与 device 建立的连接,并在 endpoint 传输数据。 |
UsbRequest | USB 请求包。 |
UsbConstants | USB 常量的定义 |
Android 系统中,USB 设备的插入和拔出是以系统广播的形式发送的,我们只要注册监听这个广播就好
public class USBReceiver extends BroadcastReceiver {
public static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
@Override
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 (device != null) {
//call method to set up device communication
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
Log.e("USBReceiver", "获取权限成功:" + device.getDeviceName());
} else {
Log.e("USBReceiver", "获取权限失败:" + device.getDeviceName());
}
}
}
}else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
// 有新的设备插入了,在这里一般会判断这个设备是不是我们想要的,是的话就去请求权限
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
// 有设备拔出了
}
}
}
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
public List getDeviceList() {
HashMap deviceList = usbManager.getDeviceList();
Iterator deviceIterator = deviceList.values().iterator();
List usbDevices = new ArrayList<>();
while (deviceIterator.hasNext()) {
UsbDevice device = deviceIterator.next();
usbDevices.add(device);
Log.e("USBUtil", "getDeviceList: " + device.getDeviceName());
}
return usbDevices;
}
/**
* mVendorId=1137,mProductId=85 佳博 3150T 标签打印机
*
* @param vendorId 厂商ID
* @param productId 产品ID
* @return device
*/
public UsbDevice getUsbDevice(int vendorId, int productId) {
HashMap deviceList = usbManager.getDeviceList();
Iterator deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext()) {
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == vendorId && device.getProductId() == productId) {
Log.e("USBUtil", "getDeviceList: " + device.getDeviceName());
return device;
}
}
Toast.makeText(context, "没有对应的设备", Toast.LENGTH_SHORT).show();
return null;
}
安卓系统对 USB 设备的使用需要得到相应的权限,这个权限要用户手动授予,或插入设备时应用到你的应用中。在使用 USB 设备前首先我们要确认一下上一节中的device是否已经获得权限,如果没有就要主动申请权限:
/**
* 判断对应 USB 设备是否有权限
*/
public boolean hasPermission(UsbDevice device) {
return usbManager.hasPermission(device);
}
/**
* 请求获取指定 USB 设备的权限
*/
public void requestPermission(UsbDevice device) {
if (device != null) {
if (usbManager.hasPermission(device)) {
Toast.makeText(context, "已经获取到权限", Toast.LENGTH_SHORT).show();
} else {
if (mPermissionIntent != null) {
usbManager.requestPermission(device, mPermissionIntent);
Toast.makeText(context, "请求USB权限", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "请注册USB广播", Toast.LENGTH_LONG).show();
}
}
}
}
注册广播:
public void registerReceiver(Activity context) {
mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
context.registerReceiver(usbReceiver, filter);
}
与 USB 设备的通信可以是同步的也可以是异步的。无论哪种情况,你都应该创建一个新线程来执行所有数据传输,避免阻塞UI线程。
第一步,打开通信端口
public boolean openPort(UsbDevice device) {
//获取设备接口,一般只有一个,多个的自己研究去
usbInterface = device.getInterface(0);
// 判断是否有权限
if (hasPermission(device)) {
// 打开设备,获取 UsbDeviceConnection 对象,连接设备,用于后面的通讯
usbConnection = usbManager.openDevice(device);
if (usbConnection == null) {
return false;
}
if (usbConnection.claimInterface(usbInterface, true)) {
Toast.makeText(Utils.getContext(), "找到 USB 设备接口", Toast.LENGTH_SHORT).show();
} else {
usbConnection.close();
Toast.makeText(Utils.getContext(), "没有找到 USB 设备接口", Toast.LENGTH_SHORT).show();
return false;
}
} else {
Toast.makeText(Utils.getContext(), "没有 USB 权限", Toast.LENGTH_SHORT).show();
return false;
}
//获取接口上的两个端点,分别对应 OUT 和 IN
for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
UsbEndpoint end = usbInterface.getEndpoint(i);
if (end.getDirection() == UsbConstants.USB_DIR_IN) {
usbEndpointIn = end;
} else {
usbEndpointOut = end;
}
}
return true;
}
第二步,发送数据
usbConnection.bulkTransfer(usbEndpointOut, bytes, bytes.length, 500);
剩余的 API 我会在项目不断完善的同时更新上来
附:demo 传送门