更新记录
1.0.0(2026-09-21)
- 首次发布
- 支持设备枚举、USB 授权、存储初始化、目录浏览、文本/二进制(Base64)读写、本地与U盘双向复制、创建目录、删除、插拔监听、所有文件访问权限检查等
平台兼容性
uni-app(4.72)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Safari | app-vue | app-vue插件版本 | app-nvue | app-nvue插件版本 | Android | Android插件版本 | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | √ | 1.0.0 | × | × | √ | 1.0.0 | √ | 1.0.0 | 5.0 | 1.0.0 | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | - | × | × |
uni-app x(4.72)
| Chrome | Safari | Android | Android插件版本 | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|---|
| × | × | 5.0 | 1.0.0 | × | × | × |
zy-usb-drive
U 盘(USB 大容量存储设备)读写 UTS 插件,移植自 uni-app 原生插件 usbDriveModule,基于
libaums(me.jahnen.libaums:core:0.10.0)直接访问 USB Host。
特性
- USB 存储设备枚举(U 盘 / 读卡器 / 移动硬盘)
- USB 授权自动申请,授权成功后自动续接初始化(无需二次点击)
- U 盘存储初始化:总容量 / 已用空间 / 剩余空间 / 簇大小 / 卷标
- 目录浏览(自动过滤
System Volume Information、LOST.DIR) - 文本文件读写(UTF-8)
- 二进制文件读写(Base64,
NO_WRAP) - 本地文件 ↔ U 盘文件双向复制(流式分块传输,支持大文件)
- 创建多级目录、删除文件/目录
- USB 插拔事件监听(插入 / 拔出)
- Android 11+ 「所有文件访问权限」检查并自动跳转系统授权页
平台支持
| 平台 | 支持 |
|---|---|
| Android | ✓ |
| iOS | ✗ |
| H5 | ✗ |
| 小程序 | ✗ |
最低 Android SDK 版本: 21 (Android 5.0) 设备须支持 USB Host(OTG)。libaums 自带
armeabi-v7a/arm64-v8a原生库。
依赖
utssdk/app-android/config.json 中已固定依赖版本:
{
"abis": ["armeabi-v7a", "arm64-v8a"],
"minSdkVersion": 21,
"dependencies": ["me.jahnen.libaums:core:0.10.0"]
}
快速开始
import {
checkAllFilesAccessPermission,
getUsbDriveDeviceList,
initUsbStorage,
registerUsbStateReceiver,
getUsbFileList,
readTextFile,
writeTextFile,
releaseResources
} from '@/uni_modules/zy-usb-drive'
标准流程
// 1. (Android 11+ 推荐)确认「所有文件访问权限」,无权限会自动跳转系统设置页
checkAllFilesAccessPermission({
success: (res) => {
console.log('是否有所有文件访问权限:', res.hasPermission)
}
})
// 2. 监听 U 盘插拔(onEvent 可多次回调)
registerUsbStateReceiver({
onEvent: (e) => {
if (e.event === 'deviceAttached') console.log('U 盘已插入')
if (e.event === 'deviceDetached') console.log('U 盘已拔出')
},
success: (res) => console.log(res.errMsg)
})
// 3. 枚举设备
getUsbDriveDeviceList({
success: (res) => {
console.log('设备列表:', res.devices)
// 4. 初始化第一个设备(无权限时会自动弹系统授权框)
initUsbStorage({
deviceIndex: res.devices[0].index,
statCapacity: true, // 需要准确的剩余/已用空间时开启;默认 false 不统计
success: (info) => {
console.log('容量:', info.capacity, '剩余:', info.freeSpace)
},
fail: (err) => console.error(err.errCode, err.errMsg)
})
}
})
// 5. 离开页面释放资源
// releaseResources()
API
所有 API 均支持 success / fail / complete 回调,失败回调参数为 UniError(含 errCode、errMsg)。
checkAllFilesAccessPermission(options?)
检查 Android 11+ 的「所有文件访问权限」,无权限时自动跳转系统授权页。
type UsbDrivePermissionResult = {
hasPermission: boolean // 是否已拥有权限
isAndroidROrHigher: boolean // 是否运行在 Android 11 及以上
jumpedToSettings: boolean // 是否已自动跳转到系统授权页
}
getUsbDriveDeviceList(options?)
枚举 USB 存储设备。
type UsbDriveDeviceInfo = {
deviceId: number
deviceName: string // 如 /dev/bus/usb/001/002
productName: string | null
manufacturerName: string | null
vendorId: number
productId: number
index: number // 供 initUsbStorage 使用
}
// success 回调: { devices: UsbDriveDeviceInfo[] }
initUsbStorage(options)
初始化指定设备(挂载其第一个分区)。
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
deviceIndex |
number |
是 | - | 设备在列表中的 index |
statCapacity |
boolean |
否 | false |
是否统计剩余/已用空间,见下方说明 |
type UsbDriveStorageInfo = {
capacity: number // 总容量(字节),总是准确
occupiedSpace: number // 已用空间(字节,含文件系统元数据占用);capacityStat 为 false 时为 0
freeSpace: number // 剩余空间(字节);capacityStat 为 false 时为 0
chunkSize: number // 簇大小(字节),总是准确
volumeLabel: string
capacityStat: boolean // 是否已统计剩余/已用空间
}
statCapacity:是否统计容量信息(默认 false)
统计剩余/已用空间需要读取 FSInfo,必要时还要扫描 FAT 表,大容量 U 盘会有一定耗时, 因此默认不统计:
| 取值 | 行为 |
|---|---|
false |
不做任何额外 IO,初始化更快;occupiedSpace / freeSpace 恒为 0,capacityStat 为 false。文件浏览与读写不受影响 |
true |
读取 FSInfo 的空闲簇计数;若该计数无效(见下)则自动扫描 FAT 表统计,返回准确数值,capacityStat 为 true |
// 需要展示准确容量时
initUsbStorage({
deviceIndex: 0,
statCapacity: true,
success: (info) => {
if (info.capacityStat) {
console.log(`已用 ${info.occupiedSpace} / 剩余 ${info.freeSpace}`)
}
}
})
关于容量数值的可靠性
occupiedSpace = capacity - freeSpace(与 libaums 语义一致),因此「已用空间」包含保留扇区、 FAT 表与根目录区占用,会略大于文件大小之和,这是正常的。部分 U 盘的 FSInfo 未写入空闲簇计数(保持
0xFFFFFFFF),而 libaums 按有符号 32 位解析成-1且未做兜底,会导致freeSpace = -1 × 簇大小(负数)、occupiedSpace超过capacity。statCapacity: true时插件在检测到该异常会自行扫描 FAT 表统计空闲簇,保证返回的freeSpace不为负; 仅当扫描也失败时才按freeSpace = 0上报(日志中会有FSInfo 空闲簇计数无效提示)。未授权时内部会自动发起 USB 授权弹窗,用户允许后自动继续初始化并回调
success; 拒绝或等待超过 60 秒会走fail(9030004/9030016)。
registerUsbStateReceiver(options?)
注册 U 盘插拔监听。注册结果走 success/fail,插拔事件走 onEvent(可多次)。
type UsbDriveEvent = {
event: string // 'deviceAttached' | 'deviceDetached'
deviceId: number
deviceName: string
}
getUsbFileList(options?)
获取指定目录下的文件列表。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string |
否 | 目录路径,缺省为根目录 / |
type UsbDriveFileInfo = {
name: string
path: string
absolutePath: string
isDirectory: boolean
size: number // 字节,目录恒为 0
}
// success 回调: { files: UsbDriveFileInfo[] }
readTextFile(options)
读取文本文件(UTF-8)。filePath 必填;success 回调 { content: string }。
readBinaryFile(options)
读取二进制文件。filePath 必填;success 回调 { base64: string }。
writeTextFile(options)
写入文本文件(UTF-8)。filePath、content 必填。文件不存在时创建,存在时覆盖。
父目录必须已存在,可先用
createUsbDirectory创建。
writeBinaryFile(options)
写入二进制文件。filePath、base64Data 必填。文件不存在时创建,存在时覆盖。
copyLocalFileToUsb(options)
把本地文件复制到 U 盘。localFilePath、usbFilePath 必填。
copyUsbFileToLocal(options)
把 U 盘文件复制到本地,本地父目录不存在时自动创建。usbFilePath、localFilePath 必填。
复制进度 onProgress
copyLocalFileToUsb 与 copyUsbFileToLocal 支持 onProgress 回调,在复制过程中
按整数百分比变化多次触发(0 ~ 100),可用于驱动进度条。
type UsbDriveCopyProgress = {
loaded: number // 已传输字节数
total: number // 待传输总字节数
progress: number // 进度百分比(0 ~ 100 的整数)
}
copyLocalFileToUsb({
localFilePath: '/sdcard/Download/video.mp4',
usbFilePath: '/video.mp4',
: (p) => {
console.log(`${p.progress}% ${p.loaded}/${p.total}`)
},
success: (res) => console.log('复制完成', res.errMsg),
fail: (err) => console.error(err.errCode, err.errMsg)
})
createUsbDirectory(options)
创建 U 盘目录,支持多级(如 /a/b/c),已存在的层级自动跳过。dirPath 必填。
deleteUsbFile(options)
删除 U 盘上的文件或目录。filePath 必填;不允许删除根目录 /。
releaseResources(options?)
释放资源:注销广播接收器、关闭已打开的 USB 设备、清空文件系统引用与待处理回调。
建议在页面 onUnload 中调用。
错误码
| 错误码 | 说明 |
|---|---|
9030001 |
参数错误 |
9030002 |
USB 存储未初始化,请先调用 initUsbStorage |
9030003 |
未检测到 USB 存储设备 |
9030004 |
USB 权限被拒绝 |
9030005 |
初始化 USB 存储失败 |
9030006 |
文件或目录不存在 |
9030007 |
获取文件列表失败 |
9030008 |
读取文件失败 |
9030009 |
写入文件失败 |
9030010 |
删除失败 |
9030011 |
创建目录失败 |
9030012 |
复制文件失败 |
9030013 |
打开权限设置页失败 |
9030014 |
应用上下文获取失败 |
9030015 |
释放资源失败 |
9030016 |
USB 权限授权超时 |
9030017 |
指定路径是目录,不能按文件读取 |
权限与要求
Android 权限已在 utssdk/app-android/AndroidManifest.xml 中声明:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.usb.host" android:required="true" />
MANAGE_EXTERNAL_STORAGE(所有文件访问权限)无法通过运行时弹窗申请, 需由用户前往系统设置手动开启,插件提供checkAllFilesAccessPermission自动跳转。
使用须知
- 必须先调用
getUsbDriveDeviceList再initUsbStorage,deviceIndex指向设备列表下标; 若中间发生插拔导致缓存失效,插件会自动重新枚举。 - 写入文件的父目录必须已存在,插件不会自动创建中间目录(与原生实现保持一致)。
- 覆盖写文件会自动截断,避免新内容较短时残留旧数据。
- 读写操作在子线程串行执行,大文件复制不会阻塞 UI。
- 拔出 U 盘后
currentFs会被清空,需重新执行getUsbDriveDeviceList+initUsbStorage。
参考
- libaums: https://github.com/magnusja/libaums
- Android USB Host 文档: https://developer.android.com/guide/topics/connectivity/usb/host

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 47
赞赏 0
下载 12627715
赞赏 1950
赞赏
京公网安备:11010802035340号