实战Android读取USB数据到手机自带存储中
实战Android读取USB数据到手机自带存储中
- 0x01 写在前面的话
- 0x02 Android 连接USB设备进行文件传输
- 2.1 添加权限
- 2.2 添加USB 读取类库
- 2.3 注册广播
- 2.4 申请读写权限
- 2.4 调用读取设备的意图
- 2.4.1 发送广播意图
- 2.4.2 拦截广播意图
- 2.4.3 设备信息初始化
- 2.4.4 递归遍历USB 设备中的所有图片
- 2.4.5 找到一个图片文件就把它保存到手机SDCard 中
0x01 写在前面的话
最近朋友在做一个手机连接单反相机实现相册直播边拍边传功能。经查资料得知,
Android 应用获取外部设备文件一共有这样四种方式
内容提供器 (Content-Provider) —已测试,独占模式, 而且需要手动点击导入到手机系统相册中才能使用
USB 传输协议 ----------------已测试,不支持单反相机,仅支持单反相机取出来内存卡数据读取
MTP传输协议 (Media Transfer Protocol)-----已测试,独占模式,可导出真实图片和缩略图
PTP 传输协议 (Picture Transfer Protocol)Digital Camera 数码相机----有同行测试成功
更多讨论方案尝试详情请移步https://github.com/geekxingyun/AndroidOtgUSBMtpSample
0x02 Android 连接USB设备进行文件传输
2.1 添加权限
首先,我们要读取USB 设备所以肯定需要USB 的读写权限,所以在
AndroidManifest.xml 中添加SD Card 的读写权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-feature android:name="android.hardware.usb.host" android:required="true" />
2.2 添加USB 读取类库
为了简化USB 设备的读取,我们添加下这个类库
implementation 'com.github.mjdev:libaums:0.5.5'
2.3 注册广播
我们需要让我们的程序知道USB 设备插入了和拔出了,这两个状态进行监听,我们这里需要用到Android 中的广播。
这里 采用动态广播注册技术
/***** * 动态注册USB 设备监听 * */ private void registerUSBReceiver() { IntentFilter intentFilter = new IntentFilter(); //自定义USB设备读取照片 intentFilter.addAction(READ_USB_DEVICE_PERMISSION); //USB连接状态发生变化时产生的广播 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); USBMTPReceiver usbmtpReceiver = new USBMTPReceiver(); registerReceiver(usbmtpReceiver, intentFilter); }
注册完广播我们还需要在OnDestroy方法里取消注册的广播
@Override protected void onDestroy() { super.onDestroy(); if (usbmtpReceiver != null) { //取消注册USB设备广播 unregisterReceiver(usbmtpReceiver); } }
2.4 申请读写权限
/*** * 请求读写权限 * ****/ private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; private static int REQUEST_PERMISSION_CODE = 1; private void requestReadAndWriteAccess(){ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE); } } } //读写权限回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION_CODE) { for (int i = 0; i < permissions.length; i++) { SmartToastUtils.showShort(MainActivity.this,"申请的权限为:" + permissions[i] + ",申请结果:" + grantResults[i]); } } }
2.4 调用读取设备的意图
2.4.1 发送广播意图
//发送USB广播 private void sendUSBBroadcast() { //发送广播 Intent intent=new Intent(READ_USB_DEVICE_PERMISSION); //发送标准广播 sendBroadcast(intent); }
2.4.2 拦截广播意图
一共有三个广播意图
- USB 设备插入监听意图
- USB 把拔出监听意图
- 自己发送读取图片广播意图
@Override public void onReceive(Context context, Intent intent) { SmartToastUtils.showShort(context,"onReceiver start"); mContext=context; final String action = intent.getAction(); switch (action) { case UsbManager.ACTION_USB_DEVICE_ATTACHED://插上USB设备 SmartToastUtils.showShort(context,"USB设备已连接"); UsbDevice find_USB_Device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); //设备不为空 if (find_USB_Device != null) { // 检查权限 permissionRequest(mContext); }else{ SmartToastUtils.showShort(mContext,"findUsb is null"); } break; case UsbManager.ACTION_USB_DEVICE_DETACHED://断开USB设备 SmartToastUtils.showShort(context,"USB设备已断开"); try { UsbDevice removedDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if(removedDevice!=null){ UsbMassStorageDevice usbMassStorageDevice=getUsbMass(removedDevice); if(usbMassStorageDevice!=null){ usbMassStorageDevice.close(); } } } catch (Exception e) { SmartToastUtils.showShort(mContext,"USB断开异常"+e.toString()); } break; case READ_USB_DEVICE_PERMISSION: //自定义读取USB 设备信息 SmartToastUtils.showShort(context,"USB已获取权限"); UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); // 检查U盘权限 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (usbDevice != null) { //读取USB 设备 readDevice(getUsbMass(usbDevice)); } else { SmartToastUtils.showShort(mContext, "没有插入U 盘"); } } else { SmartToastUtils.showShort(mContext, "未获取到 U盘权限"); permissionRequest(mContext); } break; default: break; } }
当USB 设备监听到USB设备已插入的时候,进行USB 设备的相关权限申请
申请成功后自动转到读取设备图片意图中
2.4.3 设备信息初始化
try { device.init(); } catch (IOException e) { SmartToastUtils.showShort(mContext,"device.init() error"+e.toString()); return ; } // 设备分区 Partition partition = device.getPartitions().get(0); // 文件系统 FileSystem currentFs = partition.getFileSystem(); // 获取 U 盘的根目录 UsbFile mRootFolder = currentFs.getRootDirectory(); // 获取 U 盘的容量 long capacity = currentFs.getCapacity(); // 获取 U 盘的剩余容量 long freeSpace = currentFs.getFreeSpace(); // 获取 U 盘的标识 String volumeLabel = currentFs.getVolumeLabel();
2.4.4 递归遍历USB 设备中的所有图片
private void readAllPicFileFromUSBDevice(UsbFile usbFile,FileSystem fileSystem){ try { UsbFile[] usbFileList=usbFile.listFiles(); for (UsbFile usbFileItem:usbFileList ) { if(!usbFileItem.isDirectory()){ String FileEnd = usbFileItem.getName().substring(usbFileItem.getName().lastIndexOf(".") + 1, usbFileItem.getName().length()).toLowerCase(); if(FileEnd.equals("jpg") || FileEnd.equals("png") || FileEnd.equals("gif") || FileEnd.equals("jpeg")|| FileEnd.equals("bmp")){ SmartToastUtils.showShort(mContext,"文件名称="+usbFileItem.getName()+"文件大小="+usbFileItem.getLength()); FileUtils.saveToPhoneDevice(usbFileItem,fileSystem); } }else{ readAllPicFileFromUSBDevice(usbFileItem,fileSystem); } } } catch (IOException e) { SmartToastUtils.showShort(mContext,"遍历USB文件异常"); } }
2.4.5 找到一个图片文件就把它保存到手机SDCard 中
所有读取到USB 设备上的图片会放到SDCard/usb_temp_foler 文件夹下
//SD Card 根目录下创建文件夹 private final static String USBTempFolder=Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"usb_temp_foler"; public final static void saveToPhoneDevice(UsbFile usbFile,FileSystem fileSystem){ if(usbFile.isDirectory()){ SmartLogUtils.showDebug(usbFile.getName()+"是一个文件夹",true); return ; } Boolean sdCardCanUse=Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED); if(sdCardCanUse){ SmartLogUtils.showDebug("SD Card 可用",true); }else{ SmartLogUtils.showDebug("SD Card 不可用",true); } File file=new File(USBTempFolder); //文件读写测试 if(file.canRead()){ SmartLogUtils.showError("文件可读",true); }else{ SmartLogUtils.showError("文件不可读",true); } if(file.canWrite()){ SmartLogUtils.showError("文件可写",true); }else{ SmartLogUtils.showError("文件不可写",true); } //文件夹不存在就创建 if(!file.exists()){ file.mkdir(); SmartLogUtils.showDebug("文件夹创建成功",true); }else{ SmartLogUtils.showDebug("文件夹已存在",true); } //写入文件 FileOutputStream os=null; InputStream is=null; String newFileName=null; try { newFileName=USBTempFolder+File.separator+usbFile.getName(); SmartLogUtils.showError(newFileName,true); os = new FileOutputStream(newFileName); is= new UsbFileInputStream(usbFile); int bytesRead = 0; byte[] buffer = new byte[fileSystem.getChunkSize()];//作者的推荐写法是currentFs.getChunkSize()为buffer长度 while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }finally { try { if(os!=null){ os.flush(); os.close(); } if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } }
相关代码视频讲解和本教程中的代码可移步下载
https://github.com/geekxingyun/AndroidOtgUSBMtpSample
更多相关文章
- Android刷机Root相关学习总结
- 阿里云消息推送服务
- Android(安卓)camera---Camera2详解之一 API学习
- Android(安卓)- 支持不同的设备 - 支持不同的屏幕
- Android(安卓)蓝牙串口调试程序开发
- 通过Python 获取Android设备信息的轻量级框架
- 在android平板上取位置和天气的实现方式
- Unity在Android(安卓)6.0及以上版本弹出权限申请窗口的问题
- Android开发之旅(二)服务生命周期和广播接收者生命周期