Android如何通过编程识别可移动存储中的OTG设备
Android 区分可移除存储中SD卡与OTG设备的实现方案
你当前已完成了所有存储卷的遍历逻辑,系统原生公开API在Android 13(API 33)之前没有直接区分SD卡与OTG存储的标记,可通过以下方案实现区分:
方案1:Android 13+ 官方API判断
API 33 为StorageVolume类新增了isUsb()方法,可直接判断可移除存储是否为OTG设备:
- 可移除存储中
isUsb() == true:为OTG存储 - 可移除存储中
isUsb() == false:为SD卡
方案2:低版本兼容判断
低于API 33的系统可通过反射获取隐藏字段、匹配挂载路径特征的方式区分:
- 反射调用
StorageVolume的isUsb()隐藏方法,大部分厂商ROM保留了该未公开方法 - 若反射失败,可判断存储路径关键词:OTG存储路径通常包含
usb、usbotg等字段,SD卡路径通常包含sdcard、ext_sd等字段
修改后的实现代码
fun getAvailableAllStorageVolumes(context: Context): ArrayList<StorageDirectoryParcelable> { val volumes = ArrayList<StorageDirectoryParcelable>() val sm = context.getSystemService(StorageManager::class.java) for (volume in sm.storageVolumes) { val path = getVolumeDirectory(volume) val name = volume.getDescription(context) // 新增存储类型判断逻辑 val storageType = when { volume.isPrimary || !volume.isRemovable -> "内部存储" Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { if (volume.isUsb) "OTG存储" else "SD卡" } else -> { // 低版本反射判断isUsb var isUsb = false try { val method = StorageVolume::class.java.getMethod("isUsb") isUsb = method.invoke(volume) as Boolean } catch (e: Exception) { // 反射失败则匹配路径 isUsb = path.path.contains("usb", ignoreCase = true) } if (isUsb) "OTG存储" else "SD卡" } } // 可将storageType存入你的StorageDirectoryParcelable实体类按需使用 volumes.add(StorageDirectoryParcelable(path.path, name)) Log.e("USB", "name:- $name") Log.e("USB", "存储类型:- $storageType") Log.e("USB", "isPrimary:- ${volume.isPrimary}") Log.e("USB", "isEmulated:- ${volume.isEmulated}") Log.e("USB", "isRemovable:- ${volume.isRemovable}") Log.e("USB", "state:- ${volume.state}") } return volumes }
注意事项
- 部分厂商定制ROM可能修改存储路径命名规则或隐藏系统方法,建议结合名称、路径、反射结果多维度判断,提升准确率
- 访问存储前需要提前申请对应权限:Android 12及以下申请
READ_EXTERNAL_STORAGE,Android 13及以上根据业务场景申请对应媒体权限或全文件访问权限
内容的提问来源于stack exchange,提问作者Developer_ rahul
相关产品推荐
相关产品推荐

