Android 7.0后访问文件权限:android.os.FileUriExposedException 的异常

最近项目中有一个很简单的需求:就是用系统自带图库打开在APP中下载的图片,结果就遇到了

android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/xxx.jpg exposed beyond app through Intent.getData()

的异常。

原来从Android 7.0开始,谷歌收回了访问文件的权限,即一个应用提供自身资源文件给其它应用使用时,如果给出 file://xxx 这样格式的URI的话,谷歌会认为目标应用不具备访问此文件的权限,便会抛出 FileUriExposedException 的异常。我这里的解决方法是使用 FileProvider,来生成一个content://xxx 格式的URI,并授予此 URI 临时访问权限,ok,异常解决了。下面我们来一起看看实现方式吧:

1.在 Manifest中声明FileProvider

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

            </meta-data>
        </provider>

name为 FileProvider的完整类名:android.support.v4.content.FileProvider ,是固定的;

authorities为自定义的权限名称,大家可以自定义,通常都会带上包名来避免与其他应用冲突;

exported为 false,代表只有同一个应用程序的组件或带有相同用户ID的应用程序才能使用,在 FileProvider的使用中一定要填false,否则会报错;

grantUriPermissions为true,代表允许通过接受传递的权限方式进行访问,拥有共享文件的临时权限。即如果应用A具有读取  ContentProvider 的权限,它去调用另一个应用B的activity,但是B没有读取此 ContentProvider 的权限,那么应用A可以将自己的权限通过intent传递给应用B,让其也具有访问此ContentProvider 的权限。(因此后面代码中会对Intent 进行设置: intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

2.在res下的xml文件夹中新建一个provider_paths.xml文件(名字可自定义,和上一步中resource的value一致即可)

<resources>
    <paths>
        <external-path
            name="gallery_photos"
            path=""/>
    </paths>
</resources>

内部的element可以是 files-path,cache-path,external-path等,代表的根目录分别对应为:Context.getFilesDir(),Context.getCacheDir(),Environment.getExternalStorageDirectory()等。

name是一个标识,作为根目录的名称,可以自定义;

path代表根目录下要共享的目标。

这里大家也许看的会有些困惑,我举个简单的例子:

大家都知道 ContentProvider 使用 URI 标识要操作的数据,这里的内容 URI 主要包括两部分:authority:整个提供程序的符号名称;path:指向表的名称/路径,所以内容 URI 统一的形式就是:content://authority/path。

那么当我们以上面为例,通过 FileProvider 获取到的某资源文件(比如根目录下的xxx.jpg)的uri链接即为:content://com.xxx.fileprovider/gallery_photos/xxx.jpg

3.在代码中调用(我这里就以实现用系统自带图库打开下载的一张图片为例了)

                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    Uri photoURI = FileProvider.getUriForFile(getApplicationContext(),
                            "com.xxx.fileprovider",
                            file);//file即为所要共享的文件的file
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//授予临时权限别忘了
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setDataAndType(photoURI, "image/*");
                    startActivity(intent);

ok,至此 FileProvider 的基本使用就完成了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值