获取DOCUMENT_TREE权限后访问被拒及READ_EXTERNAL_STORAGE权限咨询
问题解答
1. 关于READ_EXTERNAL_STORAGE权限的疑问
- 访问通过DOCUMENT_TREE选择的特定文件夹,不需要申请READ_EXTERNAL_STORAGE权限。从Android 10(API 29)开始,存储访问框架(SAF)的设计就是让用户主动授权访问指定目录,完全不需要依赖传统的外部存储权限。
- 如果你的状态保存类应用申请了READ_EXTERNAL_STORAGE,Play Console大概率会拒绝上架。因为该权限允许访问整个外部存储,而你的功能仅需访问用户指定的特定目录,属于过度申请权限,违反Google的权限使用规范。建议仅通过SAF实现功能,不要申请该权限。
2. 通过DOCUMENT_TREE正确获取权限并避免访问被拒
要解决访问被拒的问题,核心是正确使用SAF的权限机制,并且不要尝试获取本地文件路径,直接通过ContentResolver操作文件:
步骤1:持久化DOCUMENT_TREE权限
用户通过SAF选择目录后,必须调用takePersistableUriPermission保存权限,这样应用重启后仍能访问该目录:
// 假设通过ACTION_OPEN_DOCUMENT_TREE获取到目标目录uri val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION contentResolver.takePersistableUriPermission(uri, takeFlags)
步骤2:通过流操作复制文件,避免使用本地路径
不要试图将DOCUMENT_TREE的URI转换为本地文件路径(这在很多场景下不可行,且会触发权限问题),直接用ContentResolver打开输入输出流来复制视频:
// 源视频文件URI(来自DOCUMENT_TREE目录下) val sourceUri = ... // 目标文件URI(可通过SAF获取目标目录权限后创建,或使用应用私有目录) val targetUri = ... contentResolver.openInputStream(sourceUri)?.use { inputStream -> contentResolver.openOutputStream(targetUri)?.use { outputStream -> inputStream.copyTo(outputStream) } }
步骤3:确保目标目录的访问权限
如果是复制到外部其他文件夹,同样需要通过SAF获取该目标目录的访问权限;若复制到应用私有目录(如getExternalFilesDir()下的路径),则无需额外权限。
内容的提问来源于stack exchange,提问作者Deepesh kumar
相关产品推荐
相关产品推荐

