背景
在安卓应用中,把某个文件,复制到插入的U盘中
开发环境
win10,jdk8+,as4+
测试机型
红米Note11,android13
源码问题
文末将会提供博主整合好的源码项目连接,以供学习交流
注意
本次实战,u盘格式是fat32,其他格式,测试过,并不支持。如果有更好的想法,开源库,可以留言探讨
开源库
libaums link
开始接入
首先第一步,就是一个大坑。国内的文章,一搜索,发现都是可以列入博物馆的了,实战起来的安卓系统版本,也是很低。最近这几年更新的文章,极少。
这里用到的,就是https://github.com/magnusja/libaums这个开源库。这个库最新的版本,是0.10.0,基于kotlin进行开发的,所以还在使用java的项目,就要引入java对kotlin的支持了。
(1)java项目引入kotlin支持
项目根部build.gradle文件,声明
classpath “org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0”,如下图:
然后在开发模块build.gradle中,引入:
apply plugin: 'kotlin-android'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0"
完成上述步骤后,java就支持kotlin了。
(2)开源库版本的引入方式
博主采用的,是把开源库下载到本地,编译以后,生成aar包,再去引入到开发模块中。
这里真实一波三折,先看三方库开源库的目录:
下载完以后,在本地运行,发现有很多报错,一一修改以后,才可以正常运行。
报错一
libusbcommunication依赖的libusb编译问题,导致编译失败
报错二
项目依赖的cmake环境,有些高版本的语法需要适配
报错三
主项目中,有些没有适配安卓目标版本的方法,运行的时候报错
以上就是大概的报错类型,处理完成后,才能进行引入
引入的方式,也有很多个,其中,这个开源库作者提供了两个思路:
(1)引入libaums这个库,这个库是比较通用的,但可能有些系统适配不了
(2)引入javafs这个库,这个库是基于libaums进行开发,适配了某些场景
但是通过博主的牺牲时间式引入以后,发现两个库,在我的redmi note 11,安卓13手机上,都不能在U盘创建目录,甚至创建文件也会失败。
因此,博主就开始去看这个库的issues了。
不看不知道,一看,的确有这种情况,而作者也是爱答不理,选择性回复。这就麻了。
最后,通过不断地推敲,查看issues,发现了一种新的引入方式,就是libusbcommunication,这个可不是本地引入的,是作者写好的一个远程库,引入方式如下:
implementation("me.jahnen.libaums:libusbcommunication:0.3.0", {
exclude group: "androidx.core", module: "core-ktx"
exclude group: "androidx.core", module: "core"
exclude group: "androidx.annotation", module: "annotation-experimental"
})
implementation("me.jahnen:java-fs:0.1.4")
这里其实引入的产物,和javafs模块是接近的,不过重要的是,内部可能做了某些处理,目前可以在手机上android13系统跑通,其他系统暂未测试!
上述的引入,对于exclude排除,按项目需要进行排除即可。
(3)开始编写
因为项目中,引入这个库的目的,是为了把文件复制到u盘,所以,这里博主直接封装了一个remote service进行处理,目的是为了不影响原有项目的进程。
而最核心的操作,无非就是一下几个。
(3-1)u盘插入监听,拔出监听
那这个功能实现,用广播即可,相关类:
UsbManager.ACTION_USB_DEVICE_ATTACHED
UsbManager.ACTION_USB_DEVICE_DETACHED
(3-2)u盘读写权限申请
使用USBManager的hasPermission方法,进行判断是否拥有读取该设备的权限,否则进行权限申请,申请的代码如下:
PendingIntent permissionIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(USB_PERMISSION), PendingIntent.FLAG_MUTABLE);
getUsbManager().requestPermission(device, permissionIntent);
这里要注意的是,PendingIntent,在安卓高版本的flag。
其中,USB_PERMISSION是一个自定义广播,如果用户同意,系统则会回调该广播action,开发者只在广播接收类中,进行监听该action处理即可。
广播接收核心代码如下:
大概的意思,就是:
U盘插入–>权限申请
U盘拔出–>资源释放
授权成功–>连接U盘
(3-2)u盘连接
使用三方库提供的类:UsbMassStorageDevice进行设备获取,然后进行初始化,连接即可,示例代码如下:
可以看到有几个地方注意的:
(1)List是否为空,这个是用于获取操作文件的对象的,后续通过partition.getFileSystem()获取到操作对象进行操作。
(2)数据越界判断
通过上图中的连接操作以后,如无意外,则可以获取到UsbFileSystem操作对象了,如果获取不到,则需要根据设备,进行特定处理。
(3-2)u盘写操作
那么连接成功,又怎样进行写操作呢?
下面是相关的api:
UsbFile root = currentFs.getRootDirectory();
UsbFile[] files = root.listFiles();
for(UsbFile file: files) {
Log.d(TAG, file.getName());
if(!file.isDirectory()) {
Log.d(TAG, file.getLength());
}
}
UsbFile newDir = root.createDirectory("foo");
UsbFile file = newDir.createFile("bar.txt");
// write to a file
OutputStream os = new UsbFileOutputStream(file);
os.write("hello".getBytes());
os.close();
// read from a file
InputStream is = new UsbFileInputStream(file);
byte[] buffer = new byte[currentFs.getChunkSize()];
is.read(buffer);
详细的用法,可以参考开源库主页。
而对于某些设备,不能写入的情况,正如文章开头时所说的,通过引入方式的切换,进行尝试吧!
有更好的想法,欢迎评论区留言
源码地址链接:https://pan.baidu.com/s/1fpg1ZbboNxMK74dyf_783Q
提取码:r8k9
that’s all-----------------------------------------------------------------------------