Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/user_post_photo.jpg exposed beyond app through ClipData.Item.getUri()
这是Android7.0的“私有目录被限制访问”的问题。随着Android版本越来越高,Android对隐私的保护力度也越来越大。从Android6.0引入的动态权限控制(Runtime Permissions)到Android7.0的“私有目录被限制访问”,“StrictMode API 政策”等。
1.使用FileProvider方式
2.使用StrictMode方式
在Android7.0系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。
应对策略:若要在应用间共享文件,可以发送 content:// URI类型的Uri,并授予 URI 临时访问权限。 进行此授权的最简单方式是使用 FileProvider类。
一、指定共享的目录
为了指定共享的目录我们需要在资源(res)目录下创建一个xml目录,然后创建一个名为“file_paths”(名字可以随便起,只要和在manifest注册的provider所引用的resource保持一致即可)的资源文件,内容如下:
上述代码中path=""
,是有特殊意义的,它代码根目录,也就是说可以向其它的应用共享根目录及其子目录下的任何一个文件了,如果你将path设为path="pictures"
,那么它代表着根目录下的pictures目录(eg:/storage/emulated/0/pictures),如果你向其它应用共享pictures目录范围之外的文件是不行的。
二、在AndroidManifest清单文件中注册provider
三、使用FileProvider
/**
* 不使用StrictMode,使用fileprovide解决7.0拍照问题
*/
public void startSystemCamera2() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File pictureFile = new File(Environment.getExternalStorageDirectory().getPath() + "/" + PHOTO_OUT_PATH);
Uri pictureUri = FileProvider.getUriForFile(this, "com.seven.ps.multiple.fileprovider", pictureFile);//通过FileProvider创建一个content类型的Uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);//将拍取的照片保存到指定URI
startActivityForResult(intent, PostViewModel.REQUEST_CODE_SYSTEM_CAMERA);
}
其中getUriForFile方法获取到的内容是:
content://com.seven.ps.multiple.fileprovider/camera_photos/user_post_photo.jpg
其中camera_photos
就是file_paths.xml
中paths的name。
因为上述指定的path为path=""
,所以content://com.seven.ps.multiple.fileprovider/camera_photos/
代表的真实路径就是根目录,即:/storage/emulated/0/
。content://com.seven.ps.multiple.fileprovider/camera_photos/user_post_photo.jpg
代表的真实路径是:/storage/emulated/0/user_post_photo.jpg
。
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void initPhotoError() {
// android 7.0系统解决拍照的问题
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}
然后在初始化时调用该方法即可,这时拍照方法如下:
/**
* 使用StrictMode,不使用fileprovider解决7.0拍照问题
*/
public void startSystemCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File pictureFile = new File(Environment.getExternalStorageDirectory().getPath() + "/" + PHOTO_OUT_PATH);
Uri pictureUri = Uri.fromFile(pictureFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
startActivityForResult(intent, PostViewModel.REQUEST_CODE_SYSTEM_CAMERA);
}
至此,android 7.0拍照问题用以上两种方式任意一种都可以解决,项目中验证过。