最近在开发过程中遇到了这样一个错误,android.os.FileUriExposedException: file:///storage/emulated/0/xxx/xxx.doc exposed beyond app through Intent.getData()
出现这个问题是在使用Intent附带uri打开sd卡下的doc文件,而在Android 7.0后,应用使用 StrictMode模式,API 禁止向您的应用外公开 file://URI并且使用Intent附带uri访问本地文件时,也是需要经过授权处理的。若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用 FileProvider类
解决方法
1.在res目录下新建一个xml文件夹,在此文件夹下创建file_path.xml文件(命名任意),文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="." name="external_path"/>
<cache-path path="." name="cache_path" />
<files-path path="." name="files_path" />
<external-files-path path="." name="external_files_path" />
<external-cache-path path="." name="external_cache_path" />
</paths>
path:需要临时授权访问的路径(.代表所有路径)
name:就是你给这个访问路径起个名字
内部的element可以是files-path,cache-path,external-path,external-files-path,external-cache-path,分别对应Context.getFilesDir(),Context.getCacheDir(),Environment.getExternalStorageDirectory(),Context.getExternalFilesDir(),Context.getExternalCacheDir()等几个方法
2.在AndroidManifest.xml的标签下新增以下内容:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.demo.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path"/>
</provider>
注意:
authorities:可以自定义,但为了区分,建议用:app的包名.provider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限
exported:必须是false
resource:中的@xml/file_paths是我们接下来要添加的文件
3.在使用Intent打开文件时,做如下判断
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Uri uri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//第二个参数是manifest中定义的`authorities`
uri = FileProvider.getUriForFile(context, "com.example.demo.provider", new File(param));
} else {
uri = Uri.fromFile(new File(param));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
intent.setDataAndType(uri, "image/*");
context.startActivity(intent);