Android OTG U盘相关

不念不忘少年蓝@ 2022-11-20 08:20 255阅读 0赞

三方库

implementation 'me.jahnen:libaums:0.7.6'

权限

  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  2. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  3. <uses-feature android:name="android.hardware.usb.host" />

Note:Android 10 需要在Application标签中添加一条 android:requestLegacyExternalStorage="true" ,用于使用遗留存储权限,据说是因为安全原因。

帮助类

这里主要是用于读写图片的,如果只写文件就更简单了

  1. /**
  2. * created by Taoyuan on 2020/10/26
  3. * USB帮助类
  4. */
  5. public class UsbUtils {
  6. private Context context;
  7. private UsbMassStorageDevice mDevice;
  8. private UsbFile cFolder;
  9. private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
  10. // 文件目录
  11. public static String appDir = "App";
  12. public static String picDir = "picture";
  13. public boolean mUSBisOK = false;
  14. public UsbUtils(Context context) {
  15. this.context = context;
  16. init();
  17. }
  18. /**
  19. * 初始化广播,用于监听权限和插拔USB
  20. */
  21. private void init() {
  22. // 权限广播
  23. BroadcastReceiver mUsbPermissionActionReceiver = new BroadcastReceiver() {
  24. public void onReceive(Context context, Intent intent) {
  25. String action = intent.getAction();
  26. if (ACTION_USB_PERMISSION.equals(action)) {
  27. context.unregisterReceiver(this);//解注册
  28. synchronized (this) {
  29. UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  30. if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
  31. if (usbDevice != null) {
  32. L.e(usbDevice.getDeviceName() + "已获取USB权限");
  33. //接收到U盘插入广播,尝试读取U盘设备数据
  34. mUSBisOK = readUsbList();//U盘已插入,并获取权限
  35. }
  36. } else {
  37. L.e("USB权限已被拒绝,Permission denied for device" + usbDevice);
  38. }
  39. }
  40. }
  41. }
  42. };
  43. context.registerReceiver(mUsbPermissionActionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
  44. // otg插拔广播
  45. BroadcastReceiver mOtgReceiver = new BroadcastReceiver() {
  46. @Override
  47. public void onReceive(Context context, Intent intent) {
  48. if (intent.getAction() == null) return;
  49. switch (intent.getAction()) {
  50. case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到U盘设备插入广播
  51. T.show(context, "U盘已插入");
  52. UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  53. if (device_add != null) {
  54. //接收到U盘插入广播,尝试读取U盘设备数据
  55. mUSBisOK = readUsbList();//U盘已插入
  56. }
  57. break;
  58. case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到U盘设设备拔出广播
  59. T.show(context, "U盘已拔出");
  60. mUSBisOK = readUsbList();//U盘已拔出
  61. break;
  62. }
  63. }
  64. };
  65. //监听otg插入 拔出
  66. IntentFilter usbDeviceStateFilter = new IntentFilter();
  67. usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
  68. usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
  69. context.registerReceiver(mOtgReceiver, usbDeviceStateFilter);
  70. }
  71. /**
  72. * 读取U盘列表
  73. *
  74. * @return 是否读取成功
  75. */
  76. public boolean readUsbList() {
  77. boolean isOK = false;
  78. //设备管理器
  79. UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
  80. //获取U盘存储设备
  81. UsbMassStorageDevice[] storageDevices = UsbMassStorageDevice.getMassStorageDevices(context);
  82. PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
  83. //一般手机只有1个OTG插口
  84. for (UsbMassStorageDevice device : storageDevices) {
  85. //读取设备是否有权限
  86. if (usbManager == null) return false;
  87. if (usbManager.hasPermission(device.getUsbDevice())) {
  88. isOK = readDevice(device);
  89. } else {
  90. //没有权限,进行申请
  91. usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
  92. }
  93. }
  94. if (storageDevices.length == 0) {
  95. T.show(context, "请插入可用的U盘");
  96. }
  97. return isOK;
  98. }
  99. /**
  100. * 读取设备(需已申请权限)
  101. *
  102. * @param device usb设备
  103. * @return 是否读取成功
  104. */
  105. private boolean readDevice(UsbMassStorageDevice device) {
  106. try {
  107. mDevice = device;
  108. mDevice.init();
  109. // 一般U盘只有一个分区,在android 10 实测时,只有FAT32可以被读取
  110. if (mDevice.getPartitions().size() == 0) {
  111. T.show(context, "读取设备分区失败");
  112. return false;
  113. } else {
  114. T.show(context, "U盘已就绪");
  115. FileSystem currentFs = mDevice.getPartitions().get(0).getFileSystem();
  116. cFolder = currentFs.getRootDirectory();
  117. return true;
  118. }
  119. } catch (IOException e) {
  120. e.printStackTrace();
  121. }
  122. return false;
  123. }
  124. /**
  125. * 向USB写数据
  126. *
  127. * @param fileList 需要写入的文件
  128. * @return 是否写入成功
  129. */
  130. public boolean write(List<File> fileList) {
  131. try {
  132. // 获取usb图片目录
  133. UsbFile[] usbFiles = cFolder.listFiles();
  134. UsbFile applicationDir = null;
  135. UsbFile pictureDir = null;
  136. // 判断目录是否存在,不存在则创建
  137. for (UsbFile usbFile : usbFiles) {
  138. if (usbFile.getName().equals(appDir)) {
  139. applicationDir = usbFile;
  140. }
  141. }
  142. // app目录不存在则创建
  143. if (applicationDir == null) {
  144. applicationDir = cFolder.createDirectory(appDir);
  145. } else {
  146. // 存在则遍历pic目录
  147. for (UsbFile usbFile : applicationDir.listFiles()) {
  148. if (usbFile.getName().equals(picDir)) {
  149. pictureDir = usbFile;
  150. }
  151. }
  152. }
  153. if (pictureDir == null) {
  154. pictureDir = applicationDir.createDirectory(picDir);
  155. }
  156. // 如果不存在则直接创建
  157. if (pictureDir.listFiles().length > 0) {
  158. // 如果存在,则先把重复文件从列表中清空一遍
  159. for (UsbFile usbFile : pictureDir.listFiles()) {
  160. for (int i = fileList.size() - 1; i >= 0; i--) {
  161. if (fileList.get(i).getName().equals(usbFile.getName())) {
  162. fileList.remove(i);
  163. }
  164. }
  165. }
  166. }
  167. if (fileList.size() == 0) {
  168. T.show(context, "选择文件已全部导出");
  169. return false;
  170. }
  171. List<UsbFile> usbFileList = new ArrayList<>();
  172. for (File file : fileList) {
  173. UsbFile file1 = pictureDir.createFile(file.getName());
  174. usbFileList.add(file1);
  175. }
  176. for (UsbFile usbFile : usbFileList) {
  177. for (int i = 0; i < fileList.size(); i++) {
  178. if (fileList.get(i).getName().equals(usbFile.getName())) {
  179. write2USB(fileList.get(i).getAbsolutePath(), usbFile);
  180. }
  181. }
  182. }
  183. mDevice.close();
  184. return true;
  185. } catch (IOException e) {
  186. e.printStackTrace();
  187. }
  188. return false;
  189. }
  190. /**
  191. * 写文件
  192. *
  193. * @param source android设备中的文件路径
  194. * @param target usb目标文件
  195. */
  196. public void write2USB(String source, UsbFile target) {
  197. try {
  198. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
  199. UsbFileOutputStream usbos = new UsbFileOutputStream(target);
  200. byte[] buffer = new byte[1024];
  201. int len = -1;
  202. while ((len = bis.read(buffer)) != -1) {
  203. usbos.write(buffer, 0, len);
  204. }
  205. bis.close();
  206. usbos.flush();
  207. usbos.close();
  208. } catch (java.io.FileNotFoundException e) {
  209. L.e("The File doesn't not exist.");
  210. } catch (IOException e) {
  211. e.printStackTrace();
  212. }
  213. }
  214. }

使用

  1. UsbUtils usbUtils = new UsbUtils(this);
  2. // 加载U盘
  3. usbUtils.mUSBisOK = usbUtils.readUsbList();
  4. // 使用动态目录
  5. if (!usbUtils.mUSBisOK) {
  6. T.show(this, "请先加载U盘");
  7. return;
  8. }
  9. UsbUtils.picDir = text;
  10. // 写文件
  11. if (usbUtils.mUSBisOK) {
  12. List<File> fileList = new ArrayList<>();
  13. for (String imgPath : mData) {
  14. File file = FileUtils.getFileByPath(imgPath);
  15. if (file.exists()) fileList.add(file);
  16. }
  17. boolean writeOK = usbUtils.write(fileList);
  18. if (writeOK) T.show(
  19. this,
  20. "导出成功:" + UsbUtils.appDir + "/" + UsbUtils.picDir,
  21. true);
  22. }

发表评论

表情:
评论列表 (有 0 条评论,255人围观)

还没有评论,来说两句吧...

相关阅读

    相关 OTG 340/341开发U转232

    由于项目需要,最近用CH340芯片做了一款Android设备上的OTG产品,技术含量不大,但是为了以后查阅方便,同时希望帮助其他人,现总结如下,想到哪里就写到哪里,请大家勿怪。