求助:Android Scoped Storage本地文件目录合法Uri获取方案
解决Android Scoped Storage下统一操作内部目录与SD卡的问题
问题原因
你遇到的异常是因为 DocumentFile.fromTreeUri() 仅支持 content:// 格式的树Uri,而 DocumentFile.fromFile() 生成的是 file:// 格式的Uri,不符合该方法的要求,因此抛出"Invalid URI"异常。
可行解决方案
其实你完全不需要将内部目录转成Tree Uri,就能用同一套DocumentFile API操作内部目录和SD卡:
- 内部私有目录(
context.filesDir):直接通过DocumentFile.fromFile()获取实例,app本身拥有该目录的完整访问权限,无需额外申请权限:val internalDirDoc = DocumentFile.fromFile(context.filesDir) // 直接用DocumentFile API操作,比如列出文件、创建文件 val files = internalDirDoc.listFiles() val newFile = internalDirDoc.createFile("text/plain", "test.txt") - SD卡目录:通过SAF(存储访问框架)的
ACTION_OPEN_DOCUMENT_TREE让用户选择SD卡根目录或目标子目录,获取合法的content://树Uri后,再用DocumentFile.fromTreeUri()获取实例:// 启动SAF选择目录 val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION } startActivityForResult(intent, REQUEST_CODE_PICK_SD_DIR) // 在onActivityResult或registerForActivityResult中处理返回结果 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE_PICK_SD_DIR && resultCode == Activity.RESULT_OK) { data?.data?.let { treeUri -> // 持久化权限,避免重启后失效 context.contentResolver.takePersistableUriPermission( treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) val sdDirDoc = DocumentFile.fromTreeUri(context, treeUri) // 同样用DocumentFile API操作SD卡目录 } } }
为什么这样能统一操作
DocumentFile.fromFile()和DocumentFile.fromTreeUri()返回的都是DocumentFile实例,两者拥有完全一致的API(如listFiles()、createFile()、delete()、exists()等),你可以直接用同一套函数接收DocumentFile参数,无需区分来源。
关于获取内部目录合法Tree Uri的说明
系统不允许通过SAF或其他方式获取app私有目录的content://树Uri,因为该目录属于app私有空间,只有app本身有权限直接访问,无需通过Scoped Storage的SAF机制。强行转换只会触发异常,没有实际意义。
内容的提问来源于stack exchange,提问作者Red wine
相关产品推荐
相关产品推荐

