1. 程式人生 > >安卓7.0報錯android.os.FileUriExposedException

安卓7.0報錯android.os.FileUriExposedException

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