Android 7.0 拍照并显示照片出现"FileUriExposedException"

问题描述

拍照后显示缩略图没有问题,但是选择显示原图程序就崩溃了,抛出一个FileUriExposedException 异常.

问题原因

《第一行代码》(第二版)的第八章里的 “调用摄像头和相册”小节讲到了这个问题:

Android 7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出一个FileUriExposedException异常。

解决办法

使用FileProvider

FileProvider是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。

代码片段

// 创建File对象,用于存储拍照后的图片
File outputImage = new File(getExternalCacheDir(),
    "output_image.jpg");
//判断当前Android版本号是否大于等于24
if (Build.VERSION.SDK_INT >= 24){   
    //如果是则使用FileProvider
    imageUri = FileProvider.getUriForFile(MainActivity.this,
        "com.example.cameraalbum.fileprovider", outputImage);
} else {    
    //否则,使用原来的fromFile()
    imageUri = Uri.fromFile(outputImage);
}

其中,getUriForFile方法接受三个参数:
第一个参数要求传入Context对象,
第二个参数可以是任意唯一的字符串,
第三个参数则是之前创建的File对象。

此外,还要在AndroidManifest.xml中对内容提供器进行注册:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.camearalbum.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
         android:name="android.support.FILE_PROVIDER_PATHS"
         android:resource="@xml/file_paths"/>
</provider>

其中,android:name 属性的值是固定的,android:authoritirs 属性的值必须要和FileProvider.getUriForFile() 方法中的第二个参数一致。
另外,这里还在<provider>标签的内部使用<meta-data>来指定Uri的共享路径,并引用了一个@xml/file_paths资源。

res目录下新建一个xml目录然后新建一个file_paths.xml文件,并修改文件中的内容:

<?xml version="1.0" encoding = "utf-8"?>
<paths xmlns:app="http://schemas.android.com/apk/res/android">
    <external-path name = "my_images" path = "" />
</paths>

其中,external-path就是用来指定Uri共享的,name属性的值可以随便填,path属性的值表示共享的具体路径。这里设定空就表示将整个SD卡进行共享,也可以仅共享存放output_image.jpg 这张图片的路径。

还有一点需要注意,在Android 4.4系统之前,访问SD卡的应用关联目录也是要声明权限的,从4.4系统开始不在需要权限声明。
为了兼容老版本系统,还需要在AndroidManifest.xml 中声明一下SD卡的权限:

<uses-permission  android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

以上就可以解决Android 7.0直接使用本地真实路径的Uri会抛出FileExposedExceptiond 异常的问题了。

最后附上源码:GitHub


End

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值