Android获取所有的存储设备信息(包括外接USB存储)
获取存储设备信息
1.申请请求文件读写权限
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--Android 13 权限适配-->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:name=".MainApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Openssl">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
申请文件权限
fun requestFilePermission(context: Context, doMethod: (() -> Unit)) {
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {// Android 11以上
if (!Environment.isExternalStorageManager()) {
context.startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
} else {
doMethod.invoke()
}
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {// Android 6以上
if (PermissionUtils.isGranted(*getSdCardPermission())) {
doMethod.invoke()
} else {
PermissionUtils.permission(*getSdCardPermission())
.callback { isAllGranted, _, _, _ ->
if (isAllGranted) {
doMethod.invoke()
} else {
ToastUtils.showShort("你拒绝了权限")
}
}.request()
}
}
else -> {
doMethod.invoke()
}
}
}
private fun getSdCardPermission(): Array<String> {
return arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
}
2.获取所有的存储信息
class SdCardInfo(val baseFile: File) {
// 存储设备名称
var name: String = ""
// 可读
var canRead: Boolean = false
// 可写
var canWrite: Boolean = false
// 是否机身内置存储
var builtIn: Boolean = false
override fun toString(): String {
return "SdCardInfo(baseFile=$baseFile, name='$name', canRead=$canRead, canWrite=$canWrite, builtIn=$builtIn)"
}
}
SdCardInfoUtils:
object SdCardInfoUtils {
fun getSdCardInfoList(context: Context): MutableList<SdCardInfo> {
// 大于24使用StorageVolumes方法,否则使用getVolumes方法
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
getStorageVolumes(context)
} else {
getVolumes(context)
}
}
@SuppressLint("PrivateApi")
private fun getVolumes(context: Context): MutableList<SdCardInfo> {
val sdCardInfoList = mutableListOf<SdCardInfo>()
// 内部存储
val builtInFile = getExternalStorageDirectory()
if (builtInFile != null) {
val buildInSdCardInfo = SdCardInfo(builtInFile)
buildInSdCardInfo.canRead = builtInFile.canRead()
buildInSdCardInfo.canWrite = builtInFile.canWrite()
buildInSdCardInfo.name = "内部存储"
buildInSdCardInfo.builtIn = true
sdCardInfoList.add(buildInSdCardInfo)
}
// 外置Usb设备
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
val volumeInfoClass: Class<*>
try {
volumeInfoClass = Class.forName("android.os.storage.VolumeInfo")
val storageManagerGetVolumesMethod =
Class.forName("android.os.storage.StorageManager").getMethod("getVolumes")
val volumeInfoGetDiskMethod = volumeInfoClass.getMethod("getDisk")
val volumeInfoGetPathMethod = volumeInfoClass.getMethod("getPath")
val volumeInfoList =
(storageManagerGetVolumesMethod.invoke(storageManager) as List<Any>)
for (i in volumeInfoList.indices) {
val volumeInfo = volumeInfoList[i]
// 如果不是存储设备则返回
val diskInfo = volumeInfoGetDiskMethod.invoke(volumeInfo) ?: continue
val file = volumeInfoGetPathMethod.invoke(volumeInfo) as? File ?: continue
val sdCardInfo = SdCardInfo(file)
sdCardInfo.canRead = file.canRead()
sdCardInfo.canWrite = file.canWrite()
sdCardInfo.name = file.name
sdCardInfoList.add(sdCardInfo)
}
} catch (e: Exception) {
e.printStackTrace()
}
return sdCardInfoList
}
@RequiresApi(Build.VERSION_CODES.N)
fun getStorageVolumes(context: Context): MutableList<SdCardInfo> {
val storageInfoList = mutableListOf<SdCardInfo>()
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
val volumeList = storageManager.storageVolumes
val volumeInfoClass: Class<*> = Class.forName("android.os.storage.StorageVolume")
for (volume in volumeList) {
try {
val mFile = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
volume.directory
} else {
val volumeInfoGetDiskMethod = volumeInfoClass.getMethod("getPathFile")
volumeInfoGetDiskMethod.invoke(volume) as? File
}
if (mFile == null) continue
val storageInfo = SdCardInfo(mFile)
storageInfo.canRead = mFile.canRead()
storageInfo.canWrite = mFile.canWrite()
storageInfo.name = mFile.name
// 是否可移除
storageInfo.builtIn = !volume.isRemovable
storageInfoList.add(storageInfo)
} catch (e: Exception) {
e.printStackTrace()
}
}
return storageInfoList
}
/**
* 获取机身内存位置
* */
private fun getExternalStorageDirectory(): File? {
val extFileStatus = Environment.getExternalStorageState()
val extFile = Environment.getExternalStorageDirectory()
//首先判断一下外置SD卡的状态,处于挂载状态才能获取的到
if (extFileStatus == Environment.MEDIA_MOUNTED && extFile.exists() && extFile.isDirectory
&& extFile.canWrite()
) {
//外置SD卡的路径
return extFile
}
return null
}
}
3.测试结果
- 在Anroid10、13、14手机上测试都能获取到所有的存储设备信息;
- 在Android10以下的手机上获取的外接USB存储,一般是不能直接读写操作的,有些设备只能读不能写入,有些设备则不能读写操作,没有相关的权限;
- 对于不能读写的外接Usb,建议使用SAF进行文件读写操作;