最近在開發過程中遇到了這樣一個錯誤,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);