最近一直在给自己做减法,所以将之前保存的书签和未记录的成长一起整理 - 归纳 - 输出,此处主要记录了在开发售货机app时,因usb权限未开启,从而导致硬件设备的打印功能(USB OTG 通信)无法调用的场景处理。
- 所遇场景
- 清单授权
- 动态授权
- 兴趣扩展
如果你能看到这篇blog,你可能大概率遇到了USB相关的功能,虽然不一定能解决你的问题,但 可以把它当作一切的开始...
usb权限配置主要有以下俩种方式
AndroidMainfest 清单文件 - 静态授权
代码中动态授权 - 6.0之后记得动态权限适配
所遇场景
如果不是因为在售货机中遇到了到了下面usb相关代码的话,我平时开发应该很少能接触到usb ~
/*** 我看了一下这个方法,整体是判断某个设备的usb是否赋予权限,未授权的话就进行权限申请* */public void usbPermiss(Context context) {UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);// 获取设备HashMap<String, UsbDevice> deviceList = manager.getDeviceList();if (deviceList.size() > 0) {Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();// 这里是if不是while,说明我只想支持一种devicewhile (deviceIterator.hasNext()) {final UsbDevice device = deviceIterator.next();//Toast.makeText( this, device.toString(), Toast.LENGTH_SHORT).show();// 官方文档上边是这样写的,直接获取第一个,但往往不一定只连接一个设备,就要求我们找到自己想要的那个,一般的做法是int count = device.getInterfaceCount();for (int i = 0; i < count; i++) {UsbInterface intf = device.getInterface(i);// 之后我们会根据 intf的 getInterfaceClass 判断是哪种类型的Usb设备,// 并且结合 device.getVectorID() 或者厂家ID进行过滤,比如 UsbConstants.USB_CLASS_PRINTERif ((device.getVendorId() == 0x4b43 && device.getProductId() == 0x3538)|| (device.getVendorId() == 0x0FE6 && device.getProductId() == 0x811E)) {// 这个device就是你要找的UsbDevice,此时还需要进行权限判断// 没有权限if (!manager.hasPermission(device)) {String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);manager.requestPermission(device, mPermissionIntent);return;}}}}}}
关于Android USB 授权方式的实现,网上都在熬老汤了,千篇一律,长得都一样,此处直接借鉴、修改,方便理解、使用 ~
清单授权
AndroidMainfest - 在对应的Activity中加入以下配置
<!-- USB --><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" /><!-- USB END -->
示例
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.rxjava"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.RxJava"><activity android:name=".MainActivity"><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" /><meta-dataandroid:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"android:resource="@xml/device_filter" /></intent-filter></activity></application></manifest>
在读 device_filter
中,要了解usb设备是通过以下俩个属性来一起定义的
vendor-id 厂商id
product-id 产品id
注意:其中 device_filter
中列出了可用 usb 设备,当usb 设备连接手机之后,app 会自动询问是否允许获取该 usb 的权限。这里有一个 linux 的 usb设备厂商id 和 产品id 的汇总,可以作为 Android usb 设备的参考
<?xml version="1.0" encoding="utf-8"?>
<resources><!-- 0x0403 / 0x6001: FTDI FT232R UART --><usb-device vendor-id="1027" product-id="24577" /><!-- 0x0403 / 0x6015: FTDI FT231X --><usb-device vendor-id="1027" product-id="24597" /><!-- 0x2341 / Arduino --><usb-device vendor-id="9025" /><!-- 0x16C0 / 0x0483: Teensyduino --><usb-device vendor-id="5824" product-id="1155" /><!-- 0x10C4 / 0xEA60: CP210x UART Bridge --><usb-device vendor-id="4292" product-id="60000" /><!-- 0x067B / 0x2303: Prolific PL2303 --><usb-device vendor-id="1659" product-id="8963" /><!-- 0x1a86 / 0x7523: Qinheng CH340 --><usb-device vendor-id="6790" product-id="29987" />
</resources>
动态授权
USB权限申请
(前提是已经定位到要申请USB权限的usbdevice)
//获取USB设备ACTIONprivate static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";//获取USB设备列表及定位到要申请权限的USB设备
// UsbManager mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
// HashMap<String, UsbDevice> devices = mUsbManager.getDeviceList();
// List<UsbDevice> deviceList = new ArrayList<UsbDevice>();
// for(UsbDevice device:devices.values()){
// //获取打印机设备 vid和pid
// if (3540 == device.getVendorId() && 567 == device.getProductId()) {
// currentDevice = device;
// }
// }//开始申请USB权限private void getUsbPermission(UsbDevice mUSBDevice) {UltraLog.d("开始申请USB权限");PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);mContext.registerReceiver(mUsbReceiver, filter);// 该代码执行后,系统弹出一个对话框/等待权限mUsbManager.requestPermission(mUSBDevice, pendingIntent); //以下代码是因为在系统层将弹出框直接修改掉了,可以不用
// long start = System.currentTimeMillis();
// while (!mUsbManager.hasPermission(mUSBDevice)) {
// long current = System.currentTimeMillis();
// if ((current - start) > 3500) {
// break;
// }
// try {
// Thread.sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }}
USB广播接受者 - 动态注册
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {@SuppressLint("NewApi")public void onReceive(Context context, Intent intent) {String action = intent.getAction();if (ACTION_USB_PERMISSION.equals(action)) {synchronized (this) {mContext.unregisterReceiver(mUsbReceiver);UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)&& currentDevice.equals(device)) {//TODO 授权成功,操作USB设备} else {//用户点击拒绝了}}}}};
兴趣扩展
在查usb授权的时候,网上的主流版本就是上方的静态授权和动态授权
了,下方也是动态授权的方式,不过走的是英语注释,我脑补了一下中文注释,在此留档,愿对你有所帮助~
/*** 获得 usb 权限*/private void openUsbDevice() {//before open usb device//should try to get usb permissiontryGetUsbPermission();}UsbManager mUsbManager;private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";//获取USB权限状态private void tryGetUsbPermission() {mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);registerReceiver(mUsbPermissionActionReceiver, filter);PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);//here do emulation to ask all connected usb device for permissionfor (final UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {//add some conditional check if necessary//if(isWeCaredUsbDevice(usbDevice)){if (mUsbManager.hasPermission(usbDevice)) {//if has already got permission, just goto connect it//that means: user has choose yes for your previously popup window asking for grant perssion for this usb device//and also choose option: not ask again//有权限后的处理方式afterGetUsbPermission(usbDevice);} else {//this line will let android popup window, ask user whether to allow this app to have permission to operate this usb device//无权限则申请权限mUsbManager.requestPermission(usbDevice, mPermissionIntent);}//}}}//有usb权限后的执行逻辑private void afterGetUsbPermission(UsbDevice usbDevice) {//call method to set up device communication//Toast.makeText(this, String.valueOf("Got permission for usb device: " + usbDevice), Toast.LENGTH_LONG).show();//Toast.makeText(this, String.valueOf("Found USB device: VID=" + usbDevice.getVendorId() + " PID=" + usbDevice.getProductId()), Toast.LENGTH_LONG).show();doYourOpenUsbDevice(usbDevice);}//开始对应的usb设备private void doYourOpenUsbDevice(UsbDevice usbDevice) {//now follow line will NOT show: User has not given permission to device UsbDeviceUsbDeviceConnection connection = mUsbManager.openDevice(usbDevice);//add your operation code here}//usb权限监听者private final BroadcastReceiver mUsbPermissionActionReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();if (ACTION_USB_PERMISSION.equals(action)) {synchronized (this) {UsbDevice usbDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {//user choose YES for your previously popup window asking for grant perssion for this usb device//如果有我们usb设备的话,正常执行上方的逻辑就好if (null != usbDevice) {afterGetUsbPermission(usbDevice);}} else {//user choose NO for your previously popup window asking for grant perssion for this usb deviceToast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();}}}}};