FilePrivider
是ContentPrivider
的特殊子類粥血,是為了能安全地向其他App分享文件而定義的履因。它用content://Uri
創(chuàng)建一個(gè)文件替代Android7.0之前使用的的file://Uri
砌左。
content Uri
使用臨時(shí)的權(quán)限來允許讀寫汇四,當(dāng)你創(chuàng)建一個(gè)包含content Uri
的Intent
,為了把它發(fā)送給目標(biāo)App(client app)踏烙,你可以調(diào)用Intent.addFlags()
來添加權(quán)限,只要目標(biāo)的activity
是激活狀態(tài)历等,權(quán)限會(huì)一直存在宙帝。
對(duì)于打開Service
的Intent
,只有Service
還在運(yùn)行募闲,則權(quán)限會(huì)一直存在步脓。
作為對(duì)比,為了獲得特定file Uri
文件的權(quán)限你必須更改整個(gè)文件系統(tǒng)的權(quán)限浩螺,這樣其他所有的app都有了讀取的權(quán)限靴患,而且權(quán)限會(huì)一直存在知道你改變它。這種的讀取方式從根本上來說是不安全的要出。
下面記錄一下在Android 7.0之后如何使用(示例是打開某種文件的場景鸳君,如打開APK安裝包,打開.doc文件等)
1.menifests
中配置provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
2.創(chuàng)建filepaths.xml
文件(在res文件夾下新建xml文件夾患蹂,文件名可隨意)
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="apk"
path="/upgrade" />
<external-cache-path
name="apk"
path="/upgrade" />
</paths>
參考 FilePrivider Specifying Available Files
<paths>
標(biāo)簽下可以包含以下幾種子標(biāo)簽
<files-path name="" path="" />
其中path
對(duì)應(yīng)Context.getFilesDir()或颊,像path="/upgrade"
就是getfilesDir()
下的子文件夾upgrade
,name
可以隨意取名
<cache-path name="name" path="path" />
對(duì)應(yīng)Context.getCacheDir()
<external-path name="name" path="path" />
對(duì)應(yīng)Environment.getExternalStorageDirectory()
<external-files-path name="name" path="path" />
對(duì)應(yīng)Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)
<external-cache-path name="name" path="path" />
對(duì)應(yīng)Context.getExternalCacheDir()
3.向App外發(fā)送文件(這里是APK安裝程序)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// SDK24以上
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", apkFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
// SDK24以下
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
其中的apkFile
是文件路徑名传于,我是將下載的apk放在緩存目錄中
public static File cacheApkFile(Context context) {
File file;
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
// sdcard
file = new File(context.getExternalCacheDir(), "upgrade");
if (!file.exists()) {
file.mkdir();
}
file = new File(file, "cache.apk");
} else {
// 內(nèi)存
file = new File(context.getCacheDir(), "upgrade");
if (!file.exists()) {
file.mkdir();
}
file = new File(file, "cache.apk");
}
return file;
}
因?yàn)樵?code>cache文件夾下新建了子目錄upgrade
囱挑,所以filepaths.xml
文件需要臨時(shí)對(duì)外開放這個(gè)子目錄的權(quán)限