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

Flutter开发Android 30+应用 如何将Content URI转换为Flutter Directory

问题原因说明

你遇到的报错属于预期行为:Flutter 内置的Directory.fromUri方法仅支持file://协议的 URI 转换,安卓分区存储机制返回的content://协议 URI 无法直接映射为本地文件路径,因此会抛出不支持的操作异常。该问题和 Intent 的 Flags 配置、目录选择逻辑没有直接关联。

修复建议

1. 调整 Intent 权限配置(可选但推荐)

你当前的配置仅申请了持久化写权限,建议补充读权限避免后续读取文件报错,修改后的代码如下:

private fun selectDirectory() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    intent.addFlags(
        Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
                Intent.FLAG_GRANT_READ_URI_PERMISSION
    )
    startActivityForResult(intent, 100)
}

@RequiresApi(Build.VERSION_CODES.Q)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    val uri = data.data!!
    contentResolver.takePersistableUriPermission(
        uri,
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
    )
    return uri.toString()
}

2. 选择适配方案实现文件读写

安卓 10+ 已经禁止直接通过绝对路径访问公共目录下的文件,不存在将 content URI 转为普通 Directory 对象的通用方案,可从以下两种方案中选择适配:

方案一:原生侧处理文件读写逻辑(最稳妥)

将 XML 读写逻辑全部放到安卓原生层实现,Flutter 侧通过 MethodChannel 传递读写需求和参数。
原生侧可通过安卓官方提供的 DocumentFile API 操作目录下的文件,示例代码如下:

// 读取XML内容示例
fun readXml(uriString: String): String? {
    val treeUri = Uri.parse(uriString)
    val rootDir = DocumentFile.fromTreeUri(context, treeUri) ?: return null
    val targetFile = rootDir.findFile("example.xml") ?: return null
    return contentResolver.openInputStream(targetFile.uri)?.use { inputStream ->
        inputStream.bufferedReader().readText()
    }
}

// 写入XML内容示例
fun writeXml(uriString: String, content: String): Boolean {
    val treeUri = Uri.parse(uriString)
    val rootDir = DocumentFile.fromTreeUri(context, treeUri) ?: return false
    val targetFile = rootDir.findFile("example.xml") ?: rootDir.createFile("text/xml", "example.xml") ?: return false
    return try {
        contentResolver.openOutputStream(targetFile.uri, "wt")?.use { outputStream ->
            outputStream.write(content.toByteArray())
        }
        true
    } catch (e: Exception) {
        false
    }
}

方案二:使用第三方Flutter包封装能力

可直接引入pub.dev上适配了安卓分区存储的第三方包,这类包内部封装了DocumentFile的相关能力,无需自行编写原生代码即可直接通过content URI操作文件。


内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:24:03