Android7.0 发生的android.os.FileUriExposedException错误

  • 在Android7.0的系统上调用系统相机拍照或者进相册,便会出现android.os.FileUriExposedException错误。这是安卓7.0以上版本,做了一些系统权限更改,为了提高私有文件的安全性。禁止在您的应用外部公开 file:// URI,也就是说不能直接在应用间进行文件共享,需要URI 临时访问权限。

  • 在配置文件中加上一个provider

<!-- 如果你的app支持android7.0及以上,那么在android apk的时候临时给app授权访问文件的权限 -->
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="comxf.activity.provider.download"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_paths" />
</provider>
 android:name="android.support.v4.content.FileProvider" --> 使用 FileProvider 类

android:grantUriPermissions="true" --> uri访问授权

android:exported="false" --> 当前提供者不能被其它应用使用

android:name="android.support.FILE_PROVIDER_PATHS" --> 私有文件的路径

android:resource="@xml/file_paths" --> 指定私有文件的路径
  • 在res目录下,新建一个xml文件夹,创建一个file_paths.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path name="comxf.activity.provider.download" path="." />
    </paths>
</resources>
<external-path name="com.xf.activity.provider.download" path="." />
    name是自己起的,能识别就好了;path表示要共享文件的路径,"."表示所有路径
  • 获取图片的URI,根据不同版本生成相应的URI
    /**
     * 获取图片的URI,根据不同版本生成相应的URI
     * @param context
     * @param file
     * @return
     */
    private static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {//简单地拦截一下
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context, "comxf.activity.provider.download", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }
  • 从相机中获取图片
File imageFile;
    /**
     * 从相机中获取图片
     */
    protected void getImageFromCamera() {
        String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {// 如果挂载成功。
            Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
            // 图片路径?照相后图片要存储的位置
            picPath = getPicName();
            imageFile = new File(picPath);
            if (!imageFile.exists()){
        //getParentFile()方法返回此抽象路径名的父抽象路径名,或如果此路径名没有指定父目录则为null。
                imageFile.getParentFile().mkdirs();//重要的,,,
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//重要的,,,
                getImageByCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
            }
            // 指定输出路径
            getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, getUriForFile(PersonnelInformationActivity.this, imageFile));
            this.startActivityForResult(getImageByCamera, REQUEST_CODE_CAPTURE_CAMEIA);
        } else {
            ShowToast("请确认已经插入SD卡");
        }
    }
  • 从onActivityResult,中获取图片
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != RESULT_OK) {
        return;
    }
    // 判断请求码
    switch (requestCode) {
        case REQUEST_CODE_CAPTURE_CAMEIA:// 从相机中获取后返回
            cropPic(getUriForFile(this, imageFile));
            break;
    }
}

  • 裁剪图片
    protected void cropPic(Uri uri) {
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//重要的,,,
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intent.setAction("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");// mUri是已经选择的图片Uri
        // 下面这个crop = true是设置在开启的Intent中设置显示的VIEW可裁剪
        intent.putExtra("crop", "true");
        // aspectX aspectY 是宽高的比例,这里设置的是正方形(长宽比为1:1)
        intent.putExtra("aspectX", 1);// 裁剪框比例
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪图片宽高
        intent.putExtra("outputX", 150);// 输出图片大小
        intent.putExtra("outputY", 150);
        //裁剪时是否保留图片的比例,这里的比例是1:1
        intent.putExtra("scale", true);
        //是否是圆形裁剪区域,设置了也不一定有效
        intent.putExtra("circleCrop", true);
        //设置输出的格式
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        //是否将数据保留在Bitmap中返回
        intent.putExtra("return-data", true);
        startActivityForResult(intent, REQUEST_CODE_CROP);
    }

  • 值得注意有几个点,上面代码都有注释中都有标出

    • 1,保存图片的路径
    • 2,拍照时,要为7.0以上版本的手机添加一个,临时授权该Uri标记
    • 3,裁剪图片时,也要为7.0以上版本的手机添加一个,临时授权该Uri标记
    • 4,上面3处用这个”comxf.activity.provider.download”,为了防止出错,尽量写相同
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值