创建独立文件夹保存无损拍摄图片遇FileUriExposedException异常求修正
嘿,这个问题我太熟了!你碰到的是 Android 7.0(API 24)及以上版本的安全限制——系统不再允许直接通过 file:// URI 把文件暴露给其他应用(比如相机应用),这就是 FileUriExposedException 的由来。
错误原因分析
你直接用 Environment.getExternalStorageDirectory() 创建文件后生成了 file:// 格式的 URI,在高版本系统中,这种跨应用的文件共享属于不安全操作,系统会直接抛出异常阻止。正确的做法是用 FileProvider 生成 content:// 格式的 URI,这是 Android 官方要求的安全文件共享机制。
修正步骤
我一步步帮你改代码:
1. 在 AndroidManifest.xml 中注册 FileProvider
打开你的清单文件,在 <application> 标签内添加以下配置:
<application ...> <!-- 注册FileProvider --> <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>
- 如果你用的是旧版 support 库,把
androidx.core.content.FileProvider换成android.support.v4.content.FileProvider authorities用${applicationId}.fileprovider可以避免和其他应用冲突,也可以自定义后缀,但要保持唯一
2. 创建 FileProvider 路径配置文件
在 res 目录下新建 xml 文件夹,然后创建 file_paths.xml 文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 配置要共享的外部存储目录:myFolder --> <external-path name="my_images" path="myFolder/" /> </paths>
这个文件告诉 FileProvider,我们要共享外部存储中 myFolder 目录下的所有文件。
3. 修改代码生成安全的 URI
保留你创建文件夹的代码,然后替换生成 URI 的逻辑:
String folder_main = "myFolder"; File f = new File(Environment.getExternalStorageDirectory(), folder_main); if (!f.exists()) { f.mkdirs(); } // 生成文件名(补全你的时间戳逻辑) String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); File photoFile = new File(f, "photo_" + timeStamp + ".png"); Uri photoUri; Context context = getApplicationContext(); // 或者用当前Activity的上下文 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上,用FileProvider生成content:// URI photoUri = FileProvider.getUriForFile( context, context.getPackageName() + ".fileprovider", // 和Manifest里的authorities一致 photoFile ); // 给目标应用(比如相机)授予临时读取权限 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { // Android 7.0以下,直接用file:// URI photoUri = Uri.fromFile(photoFile); } // 把URI传给相机Intent(示例) Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(takePictureIntent, 1001); // 替换成你的请求码
额外注意事项
- 确保你的应用已经申请了
WRITE_EXTERNAL_STORAGE权限(Android 6.0及以上需要动态申请) - Android 10及以上可以考虑用 Scoped Storage,但如果你是和相机共享文件,上述 FileProvider 的方案依然适用
exported="false"必须设置为false,这是 FileProvider 的安全要求,禁止外部应用直接访问
这样修改后,就能解决 FileUriExposedException 的问题,同时也能保证图片画质不损失~
内容的提问来源于stack exchange,提问作者AbhiRam
相关产品推荐
相关产品推荐

