原文首發於微信公衆號:jzman-blog,歡迎關注交流!php
開發中常常須要將某個文件向另外一個應用程序傳遞,如圖片上傳到另外一個應用程序、文件在不一樣存儲路徑之間的複製粘貼等都須要共享文件,能夠這樣理解接收文件的應用是在向提供文件的應用發送請求。java
從 Android 7.0 開始,Android 執行 StrictMode 策略,禁止在應用外部公開 file://URL,若是在 Android 7.0 以上的應用不使用 FileProvider ,則會拋出 FileUriExposedException 異常,Android 7.0 之後要在應用之間共享文件要使用 content://URL 授予 URL 臨時訪問權限,即要使用 FileProvider 的方式來授予臨時訪問權限,具備臨時訪問權限的 URL 是安全的,這種臨時的 URL 會自動過時,其中 FileProvider 提供的 getUriForFile() 用於生成文件的內容。android
在全部狀況下,從您的應用程序向另外一個應用程序提供文件的惟一安全方法是向接收應用程序發送文件的內容URI,並授予該URI的臨時訪問權限。具備臨時URI訪問權限的內容URI是安全的,由於它們僅適用於接收URI的應用程序,而且它們會自動過時。 Android FileProvider組件提供getUriForFile()方法,用於生成文件的內容URI。安全
這裏也會提到一個在 Android 7.0 及更高版本時常常出現的異常:FileUriExposedException,經過使用 FileProvider 就能夠解決該異常,固然這也是 Android 系統在安全性上不斷完善的結果。微信
在 AndroidManifest 文件中指定 Provider,參考以下:app
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<!--android:authorities="${applicationId}.yourname"-->
<provider
android:name="android.support.v4.content.FileProvider"
<!--authorities屬性指定要用於FileProvider生成的內容URI的URI權限,通常是applicationId.yourname"組成-->
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
</manifest>
複製代碼
上面代碼中在 meta-data 目錄中指定了要共享的文件目錄,文件目錄在 filepathd.xml 中定義,可在相應的 xml 中定義的路徑有如下幾種,具體參考以下:ide
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<!--表示設備的根目錄(new File("/"))-->
<root-path name="root" path="" />
<!--表示context.getFileDir()-->
<files-path name="files" path="" />
<!--表示context.getCacheDir()-->
<cache-path name="cache" path="" />
<!--表示Environment.getExternalStorageDirectory()-->
<external-path name="external" path="" />
<!--表示context.getExternalFilesDirs()-->
<external-files-path name="name" path="path" />
<!--表示getExternalCacheDirs()-->
<external-cache-path name="name" path="path" />
</paths>
</resources>
複製代碼
在 xml 中表示某個路徑須要兩個屬性,path 表示當前指定目錄的子目錄,若是不指定則表示的是當前指定目錄下的根目錄及子目錄,name 表示會將 name 添加的 URL 後面做爲該文件的訪問路徑,參考以下:學習
//表示當前要共享的文件會在 context.getFileDir() 目錄下的 images 子目錄下查找要共享的文件
<paths>
<files-path path="images/" name="myImage" />
</paths>
//表示最終生成的共享的文件URL
content://com.example.myapp.fileprovider/myImage/image.jpg
複製代碼
最後,配置完成以後,在全部須要使用文件相關的,在獲取 Url 時應該按照以下方式獲取,具體以下:ui
public Uri getUri(File file) {
Uri uri = null;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".youName", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
複製代碼
這樣就能夠在 Android 7.0 以上愉快的共享文件了,這個知識點也算是開發中常常會遇到到。spa
能夠關注公衆號 jzman-blog,一塊兒交流學習。