如何复用Android中ACTION_OPEN_DOCUMENT_TREE返回的URI?
解决ACTION_OPEN_DOCUMENT_TREE URI持久化复用问题
问题根源
你仅保存了URI字符串,但Android对通过ACTION_OPEN_DOCUMENT_TREE获取的URI仅授予临时访问权限,应用重启后权限会被系统收回,导致复用URI时无法正常访问目录内容。必须主动申请持久化URI权限,才能跨会话复用该URI。
修正步骤
1. 获取URI时持久化权限
在onActivityResult拿到目标URI后,先调用ContentResolver.takePersistableUriPermission()保存权限,再存储URI字符串:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == directoryPickerID && resultCode == Activity.RESULT_OK) { data?.data?.also { uri -> if (uri.toString() == "content://com.android.externalstorage.documents/tree/primary%3ADocuments") { // 申请持久化读写权限(按需选择READ/WRITE) val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION contentResolver.takePersistableUriPermission(uri, takeFlags) // 验证当前访问正常(保留原逻辑) val documentsTree = DocumentFile.fromTreeUri(this, uri) ?: return val childDocuments = documentsTree.listFiles() childDocuments.forEach { doc -> doc.name?.let { Log.d("documentsUri", it) } } // 存储URI到SharedPreferences defaultSharedPreferences.edit() .putString("documentsUri", uri.toString()) .apply() } } } }
2. 复用URI的正确方式
后续会话中,直接读取存储的URI字符串并解析即可,此时因已持有持久化权限,DocumentFile能正常访问目录:
defaultSharedPreferences.getString("documentsUri", null)?.let { uriStr -> val documentsUri = Uri.parse(uriStr) // 可选:提前检查权限是否有效(避免用户手动撤销权限) val hasReadPermission = contentResolver.checkUriPermission( documentsUri, android.os.Process.myPid(), android.os.Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION ) == PackageManager.PERMISSION_GRANTED if (hasReadPermission) { val documentsTree = DocumentFile.fromTreeUri(this, documentsUri) ?: return@let val childDocuments = documentsTree.listFiles() childDocuments.forEach { doc -> doc.name?.let { Log.d("documentsUri2", it) } } } else { // 权限已失效,需重新引导用户选择目录 Log.d("documentsUri2", "目录访问权限已失效,请重新选择") } }
关键说明
takePersistableUriPermission只能在用户通过系统选择器授予权限后调用(即onActivityResult返回RESULT_OK时),无法主动申请- 持久化权限会一直保留,直到用户在系统设置中手动撤销应用对该目录的访问权限
- 若需要读写权限,必须在调用
takePersistableUriPermission时同时传入READ和WRITE标志
内容的提问来源于stack exchange,提问作者corbin
相关产品推荐
相关产品推荐

