android 7.0 因为file://引起的FileUriExposedException异常

最近作者又碰到因为android 7.0 引起的兼容问题了。

在7.0以前的版本:
//创建临时图片
File photoOutputFile = SDPath.getFile("temp.jpg", SDPath.PHOTO_FILE_STR);
Uri photoOutputUri = Uri.fromFile(photoOutputFile);

这个file文件直接非常简单的转换成"file://XXX/XXX/XXX"的uri格式

7.0后的版本:

当把targetSdkVersion指定成24及之上并且在API>=24的设备上运行时。这种方式则会出现FileUriExposedException异常

android.os.FileUriExposedException:         file:///XXX exposed beyond app through ClipData.Item.getUri()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
    at android.net.Uri.checkFileUriExposed(Uri.java:2346)
    at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8909)
    ...
原因

Android不再允许在app中把file://Uri暴露给其他app,包括但不局限于通过Intent或ClipData 等方法。

原因在于使用file://Uri会有一些风险,比如:

  • 文件是私有的,接收file://Uri的app无法访问该文件。
  • 在Android6.0之后引入运行时权限,如果接收file://Uri的app没有申请READ_EXTERNAL_STORAGE权限,在读取文件时会引发崩溃。

因此,google提供了FileProvider,使用它可以生成content://Uri来替代file://Uri

解决方案

首先在AndroidManifest.xml中添加provider

  • android:authorities
    是用来标识provider的唯一标识,在同一部手机上一个"authority"串只能被一个app使用,冲突的话会导致app无法安装。
  • android:exported必须设置成false,后面异常会讲为什么
  • android:grantUriPermissions用来控制共享文件的访问权限,也可以在java代码中设置。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.zhongjh.phone.ui"
···
</manifest >

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

res/xml/provider_paths.xml
这是指定路径和转换规则
<paths>中可以定义以下子节点

子节点对应路径例子
files-pathContext.getFilesDir() 
cache-pathContext.getCacheDir() 
external-pathEnvironment.getExternalStorageDirectory()/storage/emulated/0/
external-files-pathContext.getExternalFilesDir(null) 
external-cache-pathContext.getExternalCacheDir() 

加入我要替换的目录是
/storage/emulated/0/diary sdcard/photo/
那么配置应该写成

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

然后修改代码

//创建临时图片
File photoOutputFile = SDPath.getFile("temp.jpg", SDPath.PHOTO_FILE_STR);
//Uri photoOutputUri = Uri.fromFile(photoOutputFile);
Uri photoOutputUri = FileProvider.getUriForFile(
                    mContext,
                    mActivity.getPackageName() + ".fileprovider",
                    photoOutputFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, photoOutputUri);
我所碰到的异常处理
  • java.lang.SecurityException: Provider must not be exported
    解决方案:android:exported必须设置成false
  • Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
    解决方案:AndroidManifest.xml处的android:authorities必须跟mActivity.getPackageName() + ".fileprovider"一样


作者:qq名长是因为你没给我备注
链接:http://www.jianshu.com/p/55b817530fa3
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个异常是因为在 Android 7.0 以上的版本中,为了加强应用程序的安全性,Android 引入了一些新的限制。其中一个限制就是应用程序不能再直接使用 file:// URI 访问其他应用程序的文件。如果你的应用程序试图跨应用程序共享文件,而没有正确地使用 FileProvider API,那么就会抛出这个异常。 解决这个问题的方法是使用 FileProvider API 来共享文件。FileProvider 是一个特殊的 ContentProvider,它允许你共享你的应用程序的私有文件与其他应用程序。以下是一个简单的示例代码: 1. 在 AndroidManifest.xml 文件中添加如下内容: ```xml <application> <!-- ... --> <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> </application> ``` 2. 在 res/xml 目录下创建一个 file_paths.xml 文件,内容如下: ```xml <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths> ``` 3. 在你的代码中使用以下代码来获取 FileProvider 的 URI: ```java File photoFile = new File(getExternalFilesDir(null), "photo.jpg"); Uri photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); ``` 这样就可以使用 FileProvider API 共享你的文件了,而不会再出现 "FileUriExposedException" 异常了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值