FileProvider文件共享FileUriExposedException异常解决

26 篇文章 1 订阅

FileProvider是一个特殊的ContentProvider子类,它将 content:// Uri 代替了 file:/// Uri ,从而促进与应用程序关联的文件的安全共享.

官方文档

  • 在Android N 7.0上,没有使用FileProvider访问其他文件可能会出现如下异常:
AndroidRuntime: FATAL EXCEPTION: Thread-2
AndroidRuntime: Process: com.android.systemui:screenshot, PID: 6131
AndroidRuntime: android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/Screenshots/19700102_085501.png exposed beyond app through Intent.getData()

解决上述问题,我们需要定义一个FileProvider.

  • 1.在AndroidManifest中添加FileProvider
<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.mydomain.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        ...
    </application>
</manifest>

android:name: 指向v4包里的FileProvider类

android:authorities: content uri的基础域名,生成的uri将以content://com.mydomain.fileprovider为前缀

android:exported: 设置为 false, FileProvider 不需要被其他程序访问(为true则会报安全异常)

android:grantUriPermissions: 设为 true, 授予 URI 临时访问权限

resource: 中的@xml/file_paths是我们接下来要添加的文件

  • 2.添加允许FileProvider访问的路径

也就是上面meta-data 中的resource定义的xml(该文件添加在res/xml 目录中)

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    ...
</paths>

name="my_images" 需要临时授权访问路径名称

path="images/" 临时授权访问的路径(.代码所有路径)

根元素<paths>是固定的,内部元素可以是以下节点:

<files-path name="name" path="path" /> 对应getFilesDir() "/data/data/org.code/files"
<cache-path name="name" path="path" /> 对应getCacheDir() "/data/data/org.code/cache"
<external-path name="name" path="path" /> 对应Environment.getExternalStorageDirectory() "/storage/emulated/0"
<external-files-path name="name" path="path" /> 对应getExternalFilesDir() "/storage/emulated/0/Android/data/org.code/files"
<external-cache-path name="name" path="path" /> 对应getExternalCacheDir() "/storage/emulated/0/Android/data/org.code/cache"
  • 3.修改调用代码
Uri data;
//判断是否是AndroidN以及更高的版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    // com.mydomain.fileprovider是在清单文件中配置authorities
    data = FileProvider.getUriForFile(context, "com.mydomain.fileprovider", file);
} else {
    data = Uri.fromFile(file);
}
  • 可能会出现如下错误:

造成该问题原因是因为配置的path的路径有误.

AndroidRuntime: FATAL EXCEPTION: Thread-2
AndroidRuntime: Process: com.android.systemui:screenshot, PID: 6601
AndroidRuntime: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/Screenshots/19700102_090838.png

Android官方文档中没有找到FileProvider对外置SD卡的path设置,查看FileProvider源码.我们可以如下方式设置来对外置SD卡的支持

root-path代表/ 也就是Android设备的根目录,该目录下包含着手机内部存储器,外置SD卡等所有文件的目录.

<paths xmlns:android="http://schemas.android.com/apk/res/android>
      <root-path name="root" path="" />
</paths>
  • 可能会出现如下错误:
AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.Provider
Info.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
ent.pm.PackageManager, java.lang.String)' on a null object reference
AndroidRuntime:        at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:583)
AndroidRuntime:        at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:557)
AndroidRuntime:        at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:399)
AndroidRuntime:        at com.android.systemui.screenshot.SuperShotUtils.getImageFileIntent(SuperShotUtils.java:66)

AndroidManifest中authorities和代码中authority对应不上.

解决方案: 两个authority保持一致(还有一种情况是两者一致,但是依然报错.可以卸载apk再试,或者去掉AndroidManifest中该provider编译安装一个apk,然后加上再编译安装一个apk).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值