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

Android 10设备无法通过Intent获取非媒体文件路径问题求助

问题分析

在Android 10及以上版本,由于Scoped Storage的限制,ACTION_GET_CONTENT返回的Uri是内容URI(格式如/document/msf:<number>),这类URI并不对应文件系统中的真实路径,直接调用path属性得到的是无效字符串,无法直接用于创建File对象。

解决方案

方案一:获取外部存储文件的真实路径(仅适用于本地外部存储文件)

编写工具方法通过ContentResolver查询获取真实路径:

fun getRealPathFromUri(context: Context, uri: Uri): String? {
    val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
    val cursor = context.contentResolver.query(uri, projection, null, null, null)
    return cursor?.use {
        if (it.moveToFirst()) {
            val columnIndex = it.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)
            it.getString(columnIndex)
        } else {
            null
        }
    }
}

修改ActivityResult处理代码:

private val xfile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    var xmlFile = FileWrapperFactory(requireContext()).getAssetFileWrapper("file")
    var xmlPath = ""
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.data?.let { uri ->
            xmlPath = getRealPathFromUri(requireContext(), uri) ?: "无法获取真实路径"
            xmlFile = xmlPath.takeIf { it.isNotEmpty() && it != "无法获取真实路径" }?.let {
                FileWrapperFactory(requireContext()).getExternalFileWrapper(it)
            } ?: xmlFile
        }
    }
    viewBinding.pathName.setText(xmlPath)
}

方案二:直接通过ContentResolver操作文件(推荐,适配所有场景)

部分内容URI对应的文件可能不在本地外部存储(如云文件、其他应用私有文件),此时无法获取真实路径,推荐直接用ContentResolver打开输入流处理:

private val xfile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    var xmlFile = FileWrapperFactory(requireContext()).getAssetFileWrapper("file")
    var xmlPath = ""
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.data?.let { uri ->
            // 先记录URI,后续转为应用私有文件路径
            requireContext().contentResolver.openInputStream(uri)?.use { inputStream ->
                // 将文件复制到应用私有目录,避免Scoped Storage限制
                val privateFile = File(requireContext().filesDir, "selected_file.xml")
                FileOutputStream(privateFile).use { outputStream ->
                    inputStream.copyTo(outputStream)
                }
                xmlPath = privateFile.absolutePath
                xmlFile = FileWrapperFactory(requireContext()).getExternalFileWrapper(xmlPath)
            } ?: run {
                xmlPath = "无法打开文件"
            }
        }
    }
    viewBinding.pathName.setText(xmlPath)
}
注意事项
  • Android 10+ 中,ACTION_GET_CONTENT通过文件选择器让用户授权访问特定文件,无需额外申请READ_EXTERNAL_STORAGE权限(Android 11+ 该权限已被弱化)。
  • 若你的FileWrapper必须依赖真实路径,优先使用方案一,但需处理路径获取失败的情况;若可适配输入流操作,方案二更通用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:27:17