You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SAF创建文档并重命名后,无需额外权限如何恢复写入权限?

解决方案

核心思路:DocumentsContract.renameDocument()会返回重命名后的新Uri,直接用这个新Uri进行写入即可——它继承了原Uri的临时权限,不需要额外申请权限。

具体操作步骤:

  1. 通过ACTION_CREATE_DOCUMENT发起文件创建请求,选择保存位置后拿到初始Uri(可以用通用MIME类型,比如application/octet-stream,先不用纠结扩展名)。
  2. 调用renameDocument(),传入初始Uri和带正确扩展名的目标文件名,获取返回的新Uri。
  3. 用这个新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 10:12:50