FileProvider解決FileUriExposedException
FileUriExposedException
在給app做版本升級的時(shí)候,先從服務(wù)器下載新版本的apk文件到sdcard路徑,然后調(diào)用安裝apk的代碼,一般寫法如下:
private void openAPK(String fileSavePath){
File file=new File(fileSavePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.setDataAndType(data, "application/vnd.android.package-archive");
startActivity(intent);
}
這樣的寫法在Android7.0版本之前是沒有任何問題,只要給一個(gè)apk文件路徑就能打開安裝。但是在Android7.0版本上會報(bào)錯(cuò):
android.os.FileUriExposedException:
file:///storage/emulated/0/Download/FileProvider.apk
exposed beyond app through Intent.getData()
從Android 7.0開始,一個(gè)應(yīng)用提供自身文件給其它應(yīng)用使用時(shí),如果給出一個(gè)file://格式的URI的話,應(yīng)用會拋出FileUriExposedException。這是由于谷歌認(rèn)為目標(biāo)app可能不具有文件權(quán)限,會造成潛在的問題。所以讓這一行為快速失敗。
FileProvider方式解決
這是谷歌官方推薦的解決方案。即使用FileProvider來生成一個(gè)content://格式的URI。
1.在Manifest.xml中聲明一個(gè)provider。
<application ···>
···
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ansen.fileprovider.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
android:name值是固定的,android:authorities隨便寫但是必須得保證唯一性,我這邊用的是包名+"fileprovider",android:grantUriPermission跟android:exported固定值。
里面包含一個(gè)meta-data標(biāo)簽,這個(gè)標(biāo)簽的name屬性固定寫法,android:resource對應(yīng)的是一個(gè)xml文件。我們在res文件夾下新建一個(gè)xml文件夾,在xml文件夾下新建file_paths.xml文件。內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="name" path="Download"/>
</paths>
name表示生成URI時(shí)的別名,path是指相對路徑。
paths標(biāo)簽下的子元素一共有以下幾種:
files-path 對應(yīng) Context.getFilesDir()
cache-path 對應(yīng) Context.getCacheDir()
external-path 對應(yīng) Environment.getExternalStorageDirectory()
external-files-path 對應(yīng) Context.getExternalFilesDir()
external-cache-path 對應(yīng) Context.getExternalCacheDir()
2.當(dāng)然我們還需要修改打開apk文件的代碼
首先判斷下版本號,如果手機(jī)操作系統(tǒng)版本號大于等于7.0就通過FileProvider.getUriForFile方法生成一個(gè)Uri對象。
private void openAPK(String fileSavePath){
File file=new File(fileSavePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//判斷版本大于等于7.0
// "com.ansen.fileprovider.fileprovider"即是在清單文件中配置的authorities
// 通過FileProvider創(chuàng)建一個(gè)content類型的Uri
data = FileProvider.getUriForFile(this, "com.ansen.fileprovider.fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// 給目標(biāo)應(yīng)用一個(gè)臨時(shí)授權(quán)
} else {
data = Uri.fromFile(file);
}
intent.setDataAndType(data, "application/vnd.android.package-archive");
startActivity(intent);
}
如果你想第一時(shí)間看我的后期文章,掃碼關(guān)注公眾號,每周不定期推送Android開發(fā)實(shí)戰(zhàn)教程文章...
Android開發(fā)666 - 安卓開發(fā)技術(shù)分享
掃描二維碼加關(guān)注

浙公網(wǎng)安備 33010602011771號