android 7.0以後
為了提高私有目錄的安全性,防止應用資訊的洩漏,從 Android 7.0 開始,應用私有目錄的通路權限被做限制。具體表現為,開發人員不能夠再簡單地通過 file:// URI 通路其他應用的私有目錄檔案或者讓其他應用通路自己的私有目錄檔案。
作為四大元件之一的 ContentProvider,一直扮演着應用間共享資源的角色。這裡我們要使用到的 FileProvider,就是 ContentProvider 的一個特殊子類,幫助我們将通路受限的 file:// URI 轉化為可以授權共享的 content:// URI。
第一步 注冊一個provider
AandroidMainfest.xml 中添加:
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
注意name跟以前版本的區分,以前是 “android.support.v4.content.FileProvider” ,現在換成了 “androidx.core.content.FileProvider” 。
第二步 設定共享目錄
配合上面的 android:resource="@xml/provider_paths" ,我們在 res/xml 目錄下建立一個 provider_paths.xml 檔案:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="Download/" name= "external_images" />
</paths>
路徑可以是一個或者多個:
- files-path:内部存儲空間應用私有目錄下的 files/ 目錄,等同于 Context.getFilesDir() 所擷取的目錄路徑;
- cache-path:内部存儲空間應用私有目錄下的 cache/ 目錄,等同于 Context.getCacheDir() 所擷取的目錄路徑;
- external-path:外部存儲空間根目錄,等同于 Environment.getExternalStorageDirectory() 所擷取的目錄路徑;
- external-files-path:外部存儲空間應用私有目錄下的 files/ 目錄,等同于 Context.getExternalFilesDir(null) 所擷取的目錄路徑;
- external-cache-path:外部存儲空間應用私有目錄下的 cache/ 目錄,等同于 Context.getExternalCacheDir();
每個子元素都擁有 name 和 path 兩個屬性。
- path 屬性用于指定目前子元素所代表目錄下需要共享的子目錄名稱。注意:path 屬性值不能使用具體的獨立檔案名,隻能是目錄名。
- name 屬性用于給 path 屬性所指定的子目錄名稱取一個别名。後續生成 content:// URI 時,會使用這個别名代替真實目錄名。這樣做的目的,很顯然是為了提高安全性。
如果我們需要分享的檔案位于同級别目錄下不同的子目錄中,就需要添加多個子元素逐一指定要分享的檔案目錄,或者共享他們通用的父目錄也是可行的。
第三部 擷取url,選擇type分享
private share(String downloadFile,Context context){
Intent fileIntent = new Intent(Intent.ACTION_SEND);
fileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//給臨時權限
fileIntent.setType(getMimeType(downloadFile));//根據檔案類型設定type
//Android7.0版本以上使用FileProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fileIntent.putExtra(Intent.EXTRA_STREAM,
FileProvider.getUriForFile(context, getPackageName() +".provider",
new File(downloadFile)));
}else {
fileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(downloadFile));
}
startActivity(Intent.createChooser(fileIntent, "Share"));
}
private String getMimeType(String filePath) {
String ext = MimeTypeMap.getFileExtensionFromUrl(filePath);
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext);
}
以前直接用絕對位址的 url 就可以,Android 7 以後就需要用到 FileProvider來分享,用FileProvider.getUriForFile()方法擷取 Content URI,第二個參數就是 Manifest 檔案中注冊 FileProvider 時設定的 authorities 屬性值,第三個參數為要共享的檔案,并且這個檔案一定位于第二步我們在 path 檔案中添加的子目錄裡面。同時裡面還包含設定分享檔案類型的小技巧,根據擷取到的url實時區分檔案的種類。