參考文章:android 7.0+ FileProvider 訪問隱私文件 相冊巢块、相機(jī)礁阁、安裝應(yīng)用的適配
一巧号、概述
從 Android 7.0
開始,Android SDK 中的 StrictMode 策略禁止開發(fā)人員在應(yīng)用外部公開 file:// URI
姥闭。具體表現(xiàn)為丹鸿,當(dāng)我們在應(yīng)用中使用包含 file:// URI
的Intent
離開自己的應(yīng)用時,程序會發(fā)生FileUriExposedException
異常
這里我們要使用到的 FileProvider
棚品,就是 ContentProvider
的一個特殊子類卜高,幫助我們將訪問受限的 file:// URI
轉(zhuǎn)化為可以授權(quán)共享的 content:// URI
。
簡單來說就是在Android 7.0
及以上機(jī)型中如果需要訪問手機(jī)文件南片,那么必須使用 FileProvider
來進(jìn)行適配掺涛,否則程序會報錯。
二疼进、使用
- 在
AndroidManifest.xml
中注冊FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/files_paths" />
</provider>
注
- 這里的
authorities
可以自己定義薪缆,不過后面需要用到,只要保證前后一致即可伞广。 -
resource
內(nèi)的xml
文件是用來配置文件路徑的拣帽,文件名可自定義。
- 在
src\main\res\xml\
文件夾下創(chuàng)建對應(yīng)的files_paths.xml
文件
<!--files_paths.xml-->
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--此處的name可以隨便取-->
<external-path
name="external_storage_root"
path="."/>
<external-files-path name="document" path="Documents"/>
<external-files-path name="download" path="Download" />
<external-files-path name="pictures" path="Pictures" />
</paths>
xml
中元素必須包含一到多個子元素嚼锄。這些子元素用于指定共享文件的目錄路徑减拭,必須是這些元素之一:
-
<files-path>
:內(nèi)部存儲空間應(yīng)用私有目錄下的files/
目錄,等同于Context.getFilesDir()
所獲取的目錄路徑区丑; -
<cache-path>
:內(nèi)部存儲空間應(yīng)用私有目錄下的cache/
目錄拧粪,等同于Context.getCacheDir()
所獲取的目錄路徑; -
<external-path>
:外部存儲空間根目錄沧侥,等同于Environment.getExternalStorageDirectory()
所獲取的目錄路徑可霎; -
<external-files-path>
:外部存儲空間應(yīng)用私有目錄下的files/
目錄,等同于Context.getExternalFilesDir(null)
所獲取的目錄路徑宴杀; -
<external-cache-path>
:外部存儲空間應(yīng)用私有目錄下的cache/
目錄癣朗,等同于Context.getExternalCacheDir()
;
- 使用
FileProvider
進(jìn)行轉(zhuǎn)換:
//注意此處的 第二個參數(shù)必須與 Manifest文件中Provider 的 android:authorities 一致
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".FileProvider", outputFile);
此處需要傳進(jìn)三個參數(shù)旺罢,第一參數(shù)是context
上下文旷余,第二個參數(shù)是FileProvider
,必須與 AndroidManifest.xml
文件中Provider的 android:authorities
一致扁达,第三個參數(shù)是file
文件對象正卧。
下面再放上一個例子:
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
String type = MimeTypesTools.getMimeType(context, path);
File file = new File(path);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
uri = FileProvider.getUriForFile(mContext,
//添加這一句表示對目標(biāo)應(yīng)用臨時授權(quán)該Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);BuildConfig.APPLICATION_ID+".fileprovider", file);
}else {
uri = Uri.fromFile(file);
}
intent.setDataAndType(uri, type);
context.startActivity(intent);
劃重點(diǎn)!罩驻!
一定要給Intent
加一個flag
——Intent.FLAG_GRANT_READ_URI_PERMISSION
穗酥,否則會報Permission Denial
的錯,當(dāng)然7.0
以下的機(jī)型是不需要的惠遏。