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
相关产品推荐
相关产品推荐

