Android FileUriExposedException问题:旧多CSV文件分享代码新版本失效求助
解决Android 7.0+的FileUriExposedException问题
这个坑我踩过好多次了!你遇到的android.os.FileUriExposedException是Android 7.0(API 24)开始引入的安全限制——系统禁止App直接把file://格式的Uri暴露给其他应用,防止私有文件被随意访问。你的分享代码直接传入了原始的CSV文件Uri,大概率就是file://类型的,所以触发了异常。
下面是完整的修复方案,一步步来:
1. 在AndroidManifest.xml中注册FileProvider
FileProvider是AndroidX提供的工具,用来生成安全的content://格式Uri替代file://。先在你的清单文件里添加这个Provider:
<application> <!-- 其他已有的代码 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
android:authorities:用你的应用包名加上.fileprovider,${applicationId}会自动替换成你的包名,避免手动写错。android:exported必须设为false,因为FileProvider不需要对外暴露。android:grantUriPermissions设为true,允许临时授权其他应用访问文件。
2. 创建共享路径配置文件
在res/xml目录下新建file_paths.xml文件(如果xml目录不存在就自己建一个),用来指定哪些目录下的文件可以被共享。根据你的CSV文件存储位置调整:
比如你的CSV文件存在外部存储的MyApp/CSVs/目录下,配置如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 外部存储根目录对应Environment.getExternalStorageDirectory() --> <external-path name="my_csv_files" path="MyApp/CSVs/" /> </paths>
如果你的文件存在应用内部存储的files目录下(比如getFilesDir()),就用<files-path>标签;如果是缓存目录,用<cache-path>。
3. 修改分享代码,替换为安全的Content Uri
把原来的file:// Uri转换成FileProvider生成的content:// Uri,还要添加临时权限:
public static void sendCsvFilesToAnotherApp(final AppCompatActivity activity, final ArrayList<Uri> csvUris) { ArrayList<Uri> safeContentUris = new ArrayList<>(); // 注意这里要和Manifest里的authorities一致 String authority = activity.getPackageName() + ".fileprovider"; for (Uri originalUri : csvUris) { // 把原始的file:// Uri转换成File对象 File csvFile = new File(originalUri.getPath()); // 生成安全的content:// Uri Uri safeUri = FileProvider.getUriForFile(activity, authority, csvFile); safeContentUris.add(safeUri); } Intent sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); // 统一设置MIME类型为text/csv即可 sendIntent.setType("text/csv"); sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, safeContentUris); // 必须添加这个flag,授予接收应用临时读取权限 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 先检查有没有能处理这个Intent的应用,避免崩溃 if (sendIntent.resolveActivity(activity.getPackageManager()) != null) { activity.startActivity(Intent.createChooser(sendIntent, "分享CSV文件")); } }
额外注意事项
- 如果你的应用目标SDK是Android 10(API 29)及以上,还要注意Scoped Storage的限制:如果是访问外部存储的公共目录(比如Downloads),可能需要用
MediaStore来获取Uri,而不是直接用File;如果是应用自己创建的私有目录,上面的FileProvider方案依然有效。 - 确保所有要分享的文件都在你配置的共享路径范围内,否则FileProvider会抛出异常。
内容的提问来源于stack exchange,提问作者user9665241
相关产品推荐
相关产品推荐

