Android 11获取文件持久化权限后跨会话仍无法读写问题
问题描述
我希望让用户选择文件,实现代码如下:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); intent.setType("*/*"); startActivityForResult(intent, Aux.ACTIVITY_REQUEST_CODE_SELECT_CCRYPT_ONLY);
在Activity返回时执行以下代码:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode,resultCode,data); if (resultCode == RESULT_OK){ if (requestCode == Aux.ACTIVITY_REQUEST_CODE_SELECT_CCRYPT_ONLY){ Uri dataFileUri = data.getData(); Aux.DbugCcrypt("Storing the URI of the Work Directory In Shared Preferences: " + dataFileUri.toString()); Aux.storeStringInSharedPreferences(this,Aux.SHARED_PREF_STRING_KEY,dataFileUri.toString()); // And now we take persistent permission. ContentResolver cr = this.getContentResolver(); cr.takePersistableUriPermission(dataFileUri, (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)); } } else { // TODO Handle. Aux.DbugCcrypt("On Activity Result was not OK."); } }
我将URI字符串存入SharedPreferences并获取文件的持久化权限,随后关闭并重新打开应用,执行以下代码测试读写权限:
DbugCcrypt("Getting the Shared Preference URI"); String dataAuxUriString = getStringInSharedPreferences(context,SHARED_PREF_STRING_KEY); if (!dataAuxUriString.isEmpty()){ DbugCcrypt("Got the URI File. Testing Read/Write" ); Uri dataAuxUri= Uri.parse(dataAuxUriString); File testFile = new File(dataAuxUri.getPath()); if (testFile.isDirectory()){ DbugCcrypt("Is a directory"); } else { DbugCcrypt("Data Aux File URI. Can Read: " + testFile.canRead()); DbugCcrypt("Data Aux File URI. Can Write: " + testFile.canWrite()); } } else { DbugCcrypt("Data Aux URI String is empty"); }
得到如下日志输出(DbugCcrypt用于打印日志):
[CCRYPT_DBUG] Getting the Shared Preference URI [CCRYPT_DBUG] Got the URI File. Testing Read/Write [CCRYPT_DBUG] Data Aux File URI. Can Read: false [CCRYPT_DBUG] Data Aux File URI. Can Write: false
请问为何我无法在应用会话间获取该文件的读写权限?
问题原因与解决方案
核心问题
你用File类直接处理ACTION_OPEN_DOCUMENT返回的Uri是错误的。这类Uri是内容Uri(通常以content://开头),并非本地文件系统的路径,File类无法直接识别和访问,自然会返回canRead()和canWrite()为false。
另外,虽然你获取了持久化Uri权限,但必须通过ContentResolver来操作这个Uri,而不是绕到File类。
正确的权限验证与操作方式
要验证权限并读写文件,应该使用ContentResolver提供的方法,而不是File类:
- 验证权限:可以通过检查
ContentResolver是否能打开输入/输出流来判断权限是否有效:
DbugCcrypt("Getting the Shared Preference URI"); String dataAuxUriString = getStringInSharedPreferences(context,SHARED_PREF_STRING_KEY); if (!dataAuxUriString.isEmpty()){ DbugCcrypt("Got the URI File. Testing Read/Write" ); Uri dataAuxUri= Uri.parse(dataAuxUriString); ContentResolver resolver = context.getContentResolver(); // 测试读权限 boolean canRead = false; try (InputStream is = resolver.openInputStream(dataAuxUri)) { canRead = (is != null); } catch (IOException e) { canRead = false; } // 测试写权限 boolean canWrite = false; try (OutputStream os = resolver.openOutputStream(dataAuxUri)) { canWrite = (os != null); } catch (IOException e) { canWrite = false; } DbugCcrypt("Data Aux File URI. Can Read: " + canRead); DbugCcrypt("Data Aux File URI. Can Write: " + canWrite); } else { DbugCcrypt("Data Aux URI String is empty"); }
- 额外注意点:
- 你在
takePersistableUriPermission时同时申请了读写权限,但要确保用户选择文件时,你的Intent也声明了需要写权限。可以在启动选择Intent时添加intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);,这样系统会同时授予读写的临时权限,后续才能成功获取持久化的读写权限。 - 部分文件管理器可能不支持授予写权限,这种情况下
openOutputStream会抛出异常,需要做好错误处理。
- 你在
内容的提问来源于stack exchange,提问作者aarelovich
相关产品推荐
相关产品推荐

