Android相机FileUriExposedException求助:配置Provider仍报错
Hey,我来帮你搞定这个烦人的异常!你遇到的FileUriExposedException是Android 7.0(API 24)引入的安全机制导致的——直接用Uri.fromFile()生成的File URI会被系统判定为不安全,不允许跨应用共享,所以必须换成Content URI来实现文件共享。虽然你已经配置了Provider,但大概率是配置细节或者代码使用方式不对,下面给你完整的分步解决方案:
1. 确认Manifest中的FileProvider配置是否正确
首先,确保你在AndroidManifest.xml的<application>标签内正确配置了FileProvider,注意authorities字段要和后续代码保持完全一致,并且exported必须设为false,grantUriPermissions设为true:
<application ...> <!-- 其他组件配置 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="br.com.viniciusdeep.agenda.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
注意:如果你用的是旧版支持库而非AndroidX,把
androidx.core.content.FileProvider换成android.support.v4.content.FileProvider即可。
2. 创建文件路径配置文件
在res/xml目录下新建file_paths.xml文件(如果没有xml目录,直接右键res文件夹→New→Directory创建),配置你要共享的文件路径。因为你用的是getExternalFilesDir(null)(应用外部私有目录),所以用external-files-path标签:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- name是自定义标识,path="."表示共享该目录下所有文件 --> <external-files-path name="captured_images" path="." /> </paths>
3. 修改代码生成Content URI并授予权限
把原来生成File URI的代码替换成FileProvider生成Content URI的逻辑,同时要给拍照Intent添加临时访问权限,让相机应用能读取这个文件:
// 生成图片文件路径(和你原来的逻辑一致) String caminhoFoto = getExternalFilesDir(null) + "/" + System.currentTimeMillis() + ".jpg"; File arquivoFoto = new File(caminhoFoto); // 生成Content URI,注意第二个参数要和Manifest中的authorities完全匹配 Uri contentUri = FileProvider.getUriForFile( this, "br.com.viniciusdeep.agenda.fileprovider", arquivoFoto ); // 创建拍照Intent Intent intentImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 授予相机应用临时读取权限 intentImage.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 替换原来的File URI为Content URI intentImage.putExtra(MediaStore.EXTRA_OUTPUT, contentUri); // 启动拍照Intent(记得定义自己的请求码,比如REQUEST_CODE_TAKE_PHOTO = 100) startActivityForResult(intentImage, REQUEST_CODE_TAKE_PHOTO);
4. 拍照后的结果处理(可选但实用)
因为你已经指定了EXTRA_OUTPUT,相机应用会直接把照片保存到你创建的arquivoFoto文件中,所以在onActivityResult(或者AndroidX的registerForActivityResult)里,直接通过这个文件对象就能访问拍摄的照片,不需要从返回的Intent中取数据。
额外注意事项
- 如果你需要兼容Android 6.0(API 23)及以下,确保已经动态申请了相机权限;Android 10(API 29)及以上,因为
getExternalFilesDir属于应用私有目录,不需要申请存储权限。 - 测试时尽量用API 24及以上的设备/模拟器,确保能复现和验证修复效果。
内容的提问来源于stack exchange,提问作者Vinicius Mangueira

