使用SAF创建文档并重命名后,无需额外权限如何恢复写入权限?
解决方案
核心思路:DocumentsContract.renameDocument()会返回重命名后的新Uri,直接用这个新Uri进行写入即可——它继承了原Uri的临时权限,不需要额外申请权限。
具体操作步骤:
- 通过
ACTION_CREATE_DOCUMENT发起文件创建请求,选择保存位置后拿到初始Uri(可以用通用MIME类型,比如application/octet-stream,先不用纠结扩展名)。 - 调用
renameDocument(),传入初始Uri和带正确扩展名的目标文件名,获取返回的新Uri。 - 用这个新Uri打开输出流,直接写入数据。
Kotlin代码示例
private const val CREATE_DOC_REQUEST = 1001 // 发起创建文件请求 fun createDocument() { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/octet-stream" // 通用二进制类型,适配所有文件格式 putExtra(Intent.EXTRA_TITLE, "temp_file") // 临时占位文件名 } startActivityForResult(intent, CREATE_DOC_REQUEST) } // 处理返回结果 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == CREATE_DOC_REQUEST && resultCode == RESULT_OK) { data?.data?.let { originalUri -> val resolver = contentResolver // 替换成你需要的带扩展名的文件名 val targetFileName = "my_file.custom" val renamedUri = DocumentsContract.renameDocument(resolver, originalUri, targetFileName) renamedUri?.let { uri -> // 用新Uri写入数据 resolver.openOutputStream(uri).use { outputStream -> outputStream?.write("你的文件内容".toByteArray()) } } ?: run { // 重命名失败的处理逻辑 Toast.makeText(this, "重命名失败", Toast.LENGTH_SHORT).show() } } } }
Java代码示例
private static final int CREATE_DOC_REQUEST = 1001; // 发起创建文件请求 public void createDocument() { Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/octet-stream"); intent.putExtra(Intent.EXTRA_TITLE, "temp_file"); startActivityForResult(intent, CREATE_DOC_REQUEST); } // 处理返回结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CREATE_DOC_REQUEST && resultCode == RESULT_OK) { if (data != null && data.getData() != null) { Uri originalUri = data.getData(); ContentResolver resolver = getContentResolver(); String targetFileName = "my_file.custom"; try { Uri renamedUri = DocumentsContract.renameDocument(resolver, originalUri, targetFileName); if (renamedUri != null) { try (OutputStream outputStream = resolver.openOutputStream(renamedUri)) { outputStream.write("你的文件内容".getBytes()); } catch (IOException e) { e.printStackTrace(); } } else { Toast.makeText(this, "重命名失败", Toast.LENGTH_SHORT).show(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } } }
关键注意事项
- 原Uri在调用
renameDocument()后会立刻失去权限,必须使用返回的新Uri操作文件。 - 不需要申请
WRITE_EXTERNAL_STORAGE等额外权限,新Uri继承了原Uri的临时读写权限,在当前回调流程内直接可用。 - 如果需要在APP重启后继续操作该文件,可调用
contentResolver.takePersistableUriPermission(renamedUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)持久化权限(需在发起ACTION_CREATE_DOCUMENT的Intent中添加Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)。
内容的提问来源于stack exchange,提问作者Pavel Poley
相关产品推荐
相关产品推荐

