Scoped Storage模式下,如何检测共享存储文件夹的文件创建权限类型?
在Scoped Storage下检测指定文件夹允许创建的文件类型
在Scoped Storage模式(无MANAGE_EXTERNAL_STORAGE权限)下,确实可以通过编程方式判断指定文件夹允许创建的文件类型,核心思路是识别目录归属的系统存储类别,结合权限状态确定允许的操作:
1. 先明确不同目录的规则边界
系统公共目录的核心限制如下:
- 根目录(
/storage/emulated/0):不可写入,File.canWrite()会返回false。 - 媒体类公共目录(Pictures/DCIM/Movies/Ringtones等):仅允许创建对应类型的媒体文件(如Pictures目录只能创建图片类文件)。
- 下载/文档类目录(Download/Documents):允许创建任意类型的文件。
2. 编程检测目录归属
2.1 判断是否属于媒体类公共目录
通过对比目标目录与系统预定义的媒体目录路径,快速识别归属:
import android.os.Environment import java.io.File // 判断是否属于图片类媒体目录(Pictures/DCIM) fun isPublicImageDirectory(targetDir: File): Boolean { val publicPicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) val dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) return targetDir.absolutePath.startsWith(publicPicDir.absolutePath) || targetDir.absolutePath.startsWith(dcimDir.absolutePath) } // 判断是否属于视频类媒体目录(Movies) fun isPublicVideoDirectory(targetDir: File): Boolean { val publicVideoDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) return targetDir.absolutePath.startsWith(publicVideoDir.absolutePath) } // 判断是否属于音频类媒体目录(Ringtones/Music等) fun isPublicAudioDirectory(targetDir: File): Boolean { val ringtoneDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES) val musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) return targetDir.absolutePath.startsWith(ringtoneDir.absolutePath) || targetDir.absolutePath.startsWith(musicDir.absolutePath) }
若目标目录属于上述媒体目录,则只能创建对应MIME类型的文件(如图片目录对应image/*,视频目录对应video/*)。
2.2 判断是否属于下载/文档类公共目录
同样通过系统预定义路径对比:
// 判断是否属于Download目录 fun isPublicDownloadDirectory(targetDir: File): Boolean { val publicDownloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) return targetDir.absolutePath.startsWith(publicDownloadDir.absolutePath) } // 判断是否属于Documents目录 fun isPublicDocumentsDirectory(targetDir: File): Boolean { val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) return targetDir.absolutePath.startsWith(publicDocsDir.absolutePath) }
这类目录下,只要应用具备基础权限(Android 10及以下需WRITE_EXTERNAL_STORAGE,Android 11+无需额外权限),即可创建任意类型的文件。
3. 结合权限状态验证操作可行性
判断目录类型后,需结合当前应用权限状态确认是否能执行写入:
- 媒体目录:Android 10需
WRITE_EXTERNAL_STORAGE权限;Android 11+需对应媒体权限(如READ_MEDIA_IMAGES)或通过MediaStore插入文件(无需权限)。 - Download/Documents目录:Android 10需
WRITE_EXTERNAL_STORAGE;Android 11+直接可通过MediaStore.Downloads或ACTION_CREATE_DOCUMENT创建文件,无需权限。
通过Context.checkSelfPermission()验证权限:
import android.content.Context import android.Manifest import android.os.Build import android.content.pm.PackageManager fun hasRequiredWritePermission(context: Context, targetDir: File): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10+,媒体目录需对应媒体权限,Download/Documents目录无需权限 isPublicDownloadDirectory(targetDir) || isPublicDocumentsDirectory(targetDir) || context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED } else { // Android 9及以下,需WRITE_EXTERNAL_STORAGE权限 context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } }
总结
通过目录归属判断+权限验证的组合方式,可准确得出指定文件夹允许创建的文件类型:
- 媒体目录:仅允许对应类型的媒体文件
- Download/Documents目录:允许任意类型文件
- 其他目录:不可写入
内容的提问来源于stack exchange,提问作者Alexey Ozerov
相关产品推荐
相关产品推荐

