小米手机裁剪图片报错java.lang.SecurityException

前言

众所周知Android7.0提高了安全防护,不允许应用内部Uri暴露给外部,因此引入了FileProvider。有关FileProvider的使用和配置,这里就不赘述了。我这里出现的问题是选择图片在小米手机出现crash,拍照图片无法加载,而其他手机则正常。

  • 使用FileProvider构建的Uri是以Content://开头的,而使用Uri.fromFile()创建的是以file:///开头的;

代码出现bug

图片裁剪代码如下:

private boolean corp(Activity activity, Uri uri) {
        Intent cropIntent = new Intent("com.android.camera.action.CROP");
        cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        cropIntent.setDataAndType(uri, "image/*");
        cropIntent.putExtra("crop", "true");
        cropIntent.putExtra("aspectX", 1);
        cropIntent.putExtra("aspectY", 1);
        cropIntent.putExtra("outputX", 200);
        cropIntent.putExtra("outputY", 200);
        cropIntent.putExtra("noFaceDetection", true);
        cropIntent.putExtra("return-data", false);
        cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

        File dir = new File(Environment.getExternalStorageDirectory().getPath() , "avatar_image");
        if (!dir.exists() && dir.mkdirs()) ;
        File fileCrop  = new File(dir, CROP_FILE_NAME);
        if (!fileCrop.exists()) {
            try {
                fileCrop.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        cropImageUri = Uri.fromFile(fileCrop);
        cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
        activity.startActivityForResult(cropIntent, INTENT_CROP);
    }
  1. 选择图片报错
Caused by: java.lang.SecurityException: Uid 10797 does not have permission to uri 0 @ content://com.miui.gallery.open/raw/...20180921_202403.jpg

这里的Uri已经是Gallery产生的了,为什么还是报错呢?
看有帖子说是需要去掉intent.addFlag即可。

  1. 于是我照做了,但是Camera拍照又出现问题了:弹出toast无法加载此图片

思考为什么:

Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION

这个flag为Intent赋予了临时权限,允许读写传入的uri,也就是被裁剪的图片文件;

  • 拍照时Uri是FileProvider生成的:content://com.xxx.packagename/avatar_image/photo_file.jpg,是应用内部文件,对外开放需要临时权限;
  • 选择图片Uri是:content://com.miui.gallery.open/raw/...,是小米相册ContentProvider生成的,因此对所有应用开放,不需要临时权限。
  • 裁剪是该应用调用系统裁剪接口,是从本应用去到外部应用;
    因此这里的Uri需要区别对待:
   private boolean corp(Activity activity, Uri uri, boolean fromCamera) {
        Intent cropIntent = new Intent("com.android.camera.action.CROP");
        if (fromCamera){
            cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
       ...

至此,该问题解决

总结:

  1. 如果是App内部Uri,需要通过FileProvider构建和暴露给外部,并添加临时权限;如果不是App内部的,则不必添加临时权限;关键:明确资源来源,和资源去向
  2. Android不断提升的安全和权限限制,例如 Android 9.0建议使用HTTPS访问,不然会抛出异常java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy;因此安卓为开发者提出了更多更高要求,需要开发者不断提高安全意识,也令应用开发不断规范化,为安卓点赞!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值