Android获取SD卡路径问题:已获全文件权限仍无法访问外置SD卡
问题:Android 11+下获取外置SD卡绝对路径用于照片整理
我正在开发一款自用的照片整理APP,需求是按照片创建日期将其分类到2023-01、2023-02这类命名的文件夹中。照片存储在外置SD卡,但目前无法访问该SD卡:已授予ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION权限,但以下方法均无法获取SD卡真实路径:
context.getExternalFilesDirs(null)返回的数组中有一个元素为null;Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)指向内部存储;File("/sdcard")实际访问的是内部存储而非SD卡。
我需要获取类似/storage/7B32-B4556/这样的真实SD卡路径。也曾尝试调用以下代码选择SD卡目录,但得到的是模糊的content URI,且无法从中获取绝对文件路径,我不想使用存储API:
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) chooseDirectoryRequestLauncher.launch(intent)
项目API配置
compileSdk 34 defaultConfig { applicationId "com.cndgf.photosorter" minSdk 30 targetSdk 34 versionCode 1 versionName "1.0" }
Manifest权限配置
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.PERMISSIONS_STORAGE" /> <uses-permission android:name="android.permission.REQUEST_EXTERNAL_STORAGE" />
解决方案
1. 清理无效权限
Manifest中的PERMISSIONS_STORAGE和REQUEST_EXTERNAL_STORAGE并非Android官方定义的权限,直接删除即可。保留MANAGE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE三个有效权限。
2. 获取外置SD卡真实路径的可行代码
在Android 10+环境下,拥有MANAGE_EXTERNAL_STORAGE权限时,可通过系统存储服务遍历挂载卷获取SD卡路径:
fun getExternalSdCardPath(context: Context): String? { val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager val storageVolumes = storageManager.storageVolumes for (volume in storageVolumes) { // 跳过内部存储 if (volume.isPrimary) continue // 仅处理已挂载的可访问卷 if (volume.state == Environment.MEDIA_MOUNTED) { val path = volume.directory?.absolutePath if (path != null && path.startsWith("/storage/")) { return path } } } return null }
3. 确保权限已正确授予
MANAGE_EXTERNAL_STORAGE权限需要用户手动到系统设置开启,需在代码中检查并引导:
// 检查权限状态 fun hasManageStoragePermission(context: Context): Boolean { return Environment.isExternalStorageManager() } // 引导用户开启权限 fun requestManageStoragePermission(context: Context) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:${context.packageName}") context.startActivity(intent) }
4. 关键注意事项
- 部分设备SD卡路径格式可能略有差异,但
StorageVolume.directory返回的是系统认可的真实可访问路径; - 操作前需确认SD卡处于
MEDIA_MOUNTED状态,避免读写失败; - 禁止硬编码SD卡路径,不同厂商设备挂载路径可能存在区别。
内容的提问来源于stack exchange,提问作者ferdinand
相关产品推荐
相关产品推荐

