创建独立拍照图片文件夹时触发FileUriExposedException求助
嘿,这个问题我之前帮好几个开发者捋顺过,是Android 7.0(API 24)及以上版本的安全限制搞的鬼——系统不再允许直接把file://类型的URI暴露给其他应用,不然就会抛出你遇到的android.os.FileUriExposedException。别慌,用FileProvider就能完美解决,一步步来:
1. 在Manifest里注册FileProvider
打开你的AndroidManifest.xml,在<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>
android:authorities要保证唯一,用${applicationId}.fileprovider就很稳妥,避免和其他应用冲突exported必须设为false,因为FileProvider不需要对外暴露grantUriPermissions设为true,允许我们给其他应用临时访问权限
2. 创建文件路径配置文件
在res目录下新建一个xml文件夹(如果没有的话),然后创建file_paths.xml文件,用来指定我们要共享的文件目录。你的图片存在外部存储的MyImages文件夹里,所以配置如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- external-path对应外部存储根目录,path是你的目标文件夹名 --> <external-path name="my_images" path="MyImages/" /> </paths>
name是给这个目录取的别名,随便填就行,主要是为了安全隐藏真实路径。
3. 修改代码生成安全的Uri
把原来直接用Uri.fromFile()生成Uri的逻辑,换成FileProvider.getUriForFile(),并且给目标应用加上临时访问权限。比如你是调用相机拍照存储的场景,代码改成这样:
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "MyImages"); imagesFolder.mkdirs(); Random generator = new Random(); int n = 10000; n = generator.nextInt(n); File imageFile = new File(imagesFolder, "FILENAME_" + n + ".jpg"); // 生成安全的content://类型Uri Uri imageUri = FileProvider.getUriForFile( getApplicationContext(), getPackageName() + ".fileprovider", // 和Manifest里的authorities一致 imageFile ); // 如果是启动相机的Intent,记得添加权限flag Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 给相机应用临时读写权限 cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); startActivityForResult(cameraIntent, YOUR_REQUEST_CODE); // 替换成你的请求码
如果是分享文件给其他应用,同样要加上这两个权限flag,确保对方应用能正常访问文件。
补充说明
为什么会触发这个异常?Android 7.0引入了StrictMode API,严格限制了跨应用的文件访问,file://Uri会直接暴露文件的真实路径,存在权限泄露风险;而FileProvider是ContentProvider的子类,它会把file://转换成content://类型的Uri,并且可以通过临时授权的方式,安全地让其他应用访问指定文件。
内容的提问来源于stack exchange,提问作者AbhiRam

