Android 13中使用FileProvider打开文件遇「文件未找到」错误求助
问题原因分析
- FileProvider路径配置错误:你的FileProvider可能未正确映射公共Download目录。Android 10及以上版本中,公共存储目录需要使用
<external-public-path>标签配置,若paths.xml里用了错误的标签(比如<external-path>),会导致FileProvider生成的URI无法被正确解析——即便本地文件存在,第三方应用也找不到对应资源。 - 系统应用对自定义FileProvider的兼容性问题:部分系统自带的HTML查看器仅信任系统级Content Provider(如MediaStore)的URI,对第三方App的FileProvider URI支持不足,导致无法识别路径。
- Android 13存储权限限制:Android 13收紧了公共存储非媒体文件的访问权限,仅通过已废弃的
READ_EXTERNAL_STORAGE无法直接访问Download目录的文本文件;file.exists()能检测到文件是因为该方法不严格校验权限,但实际读取时会被系统限制。
解决方案建议
1. 修正FileProvider的路径配置
确保res/xml/file_paths.xml正确映射公共Download目录:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 映射公共Download目录 --> <external-public-path android:name="Download" android:path="Download" /> </paths>
同时确认AndroidManifest中FileProvider的配置正确引用该文件:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.telit.downloaddemo.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
2. 改用MediaStore获取系统信任的Content URI
系统应用对MediaStore生成的URI兼容性更好,通过查询MediaStore获取Download目录下文件的URI:
private fun openFile(fileName: String) { // 先通过MediaStore获取文件URI val mediaUri = getMediaStoreDownloadUri(fileName) if (mediaUri != null) { val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(mediaUri, "text/plain") addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } try { startActivity(intent) } catch (e: ActivityNotFoundException) { Toast.makeText(this, "无可用应用打开文件", Toast.LENGTH_SHORT).show() } catch (e: Exception) { Log.e(TAG, "打开文件失败: ${e.message}", e) } } else { Toast.makeText(this, "文件未找到", Toast.LENGTH_SHORT).show() } } private fun getMediaStoreDownloadUri(fileName: String): Uri? { val projection = arrayOf(MediaStore.Downloads._ID) val selection = "${MediaStore.Downloads.DISPLAY_NAME} = ?" val selectionArgs = arrayOf(fileName) val sortOrder = "${MediaStore.Downloads.DATE_ADDED} DESC" contentResolver.query( MediaStore.Downloads.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)) return ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, id) } } return null }
该方法无需额外申请特殊权限,且系统应用能正常识别URI。
3. 备选:申请MANAGE_EXTERNAL_STORAGE权限(不推荐)
若上述方法无效,可申请全文件访问权限,但该权限属于特殊权限,需要用户手动在设置中开启,且Google Play审核可能限制此类权限的使用:
- 在AndroidManifest中添加权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- 代码中引导用户开启权限:
if (!Environment.isExternalStorageManager()) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:$packageName") startActivity(intent) }
内容的提问来源于stack exchange,提问作者Akash Adhkary
相关产品推荐
相关产品推荐

