最近在开发过程中遇到了这样一个错误,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的<application></application>标签下新增以下内容:
<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/provider_paths"/> </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);