首页 > 系统 > Android > 正文

兼容Android N 调用相册和相机获取图片及Crash- FileUriExposedException解决方案

2019-11-09 17:56:57
字体:
来源:转载
供稿:网友

原因

Android N 文件系统权限发生了变化 ,为了提高私有文件的安全性,在targetSdk版本为N或者以后版本的app中,其私有目录将会限制访问。这可以防止私有文件元数据的泄露,比如文件大小或者是文件是否存在。但这给开发者带来了很多不利的影响:

文件的owner不能放宽文件权限,如果你使用MODE_WORLD_READABLE或者 MODE_WORLD_WRITEABLE操作文件,将会触发SecurityException。

当你跨package域传递file://的URI时,接收者得到的将是一个无权访问的路径,因此,这将会触发FileUriExposedException。


解决方案

对于这类操作,官方推荐的方式是使用FilePRovider,当然你也可以使用ContentProvider。


源代码

public void camera() { String savePath = Environment.getExternalStorageDirectory(); String tempFileName = "temp.jpg" Intent intent = null; // 判断存储卡是否可以用,可用进行存储 if (StorageUtils.hasSdcard()) { //设定拍照存放到自己指定的目录,可以先建好 File file = new File(savePath); if(!file.exists()){ file.mkdirs(); } Uri pictureUri; File pictureFile = new File(savePath, tempFileName); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, pictureFile.getAbsolutePath()); pictureUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues); }else { intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); pictureUri = Uri.fromFile(pictureFile); } if (intent != null) { intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri); startActivityForResult(intent, PHOTO_REQUEST_CAMERA); } } } /** * 从相册获取 */ public void gallery() { // 激活系统图库,选择一张图片 Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, PHOTO_REQUEST_GALLERY); } /** *选择图片返回结果处理 */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == PHOTO_REQUEST_GALLERY) {//相册 if (data != null) { // 得到图片的全路径 Uri uri = data.getData(); if (uri != null) { tempPhotoPath = savePath + "/" + tempFileName; //do something }else { Log.e("jaygoo","获取图片失败!"); } } } else if (requestCode == PHOTO_REQUEST_CAMERA) {//照相 /* 1.好些设备在调用系统相机照相后返回的 data为null 解决办法就是在调用相机之前先设定好照片的路径和名称,拍完后直接拿来用 2.如果图片地址没有图片存在,则表示没有进行照相 */ tempPhotoPath = savePath + "/" + tempFileName; File file = new File(tempPhotoPath); if (file != null && file.exists()) { Uri uri = Uri.fromFile(file); try { StorageUtils.saveFile(file, IMAGE_DIR); } catch (IOException e) { e.printStackTrace(); } //do something }else { DialogToast.getInstance().showErrorToast("获取图片失败!"); } } } else if (resultCode == UCrop.RESULT_ERROR) { Log.e("jaygoo","获取图片失败!"); } super.onActivityResult(requestCode, resultCode, data); }

扩展

这里兼容我采用的是ContentProvider,当然也可以使用Google官方推荐的FileProvider,这里我给出地址Demo,有兴趣的可以看下。FileProvider Demo


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表