前言
Andrid 7.0 繼續(xù)提高了對用戶隱私的保護和系統(tǒng)安全性,直接禁止掉了 file:// 協(xié)議,我們通常使用下面的代碼安裝apk就會出現(xiàn)問題:
/**
* 調(diào)用系統(tǒng)安裝應用
*/
public static boolean install(Context context, File file) {
if (file == null || !file.exists() || !file.isFile()) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return true;
}
在 7.0 的設備上運行的時候會報 FileUriExposedException (文件Uri暴露)錯誤:
Caused by: android.os.FileUriExposedException
解決辦法是通過定義 FileProvider,觀察發(fā)現(xiàn)使用的是content:// 協(xié)議
清單文件中定義 FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.graypn.android_common.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
注意下 authorities字段,同一個手機上,只能有一個名字為這個 authorities 的 Provider ,不能重復。
這里的 meta-data 設置了可訪問的文件路徑。
添加可訪問的文件目錄
在res目錄下,增加xml文件夾,并新建一個名為 file_paths.xml 的文件。文件內(nèi)容格式如下:
<paths>
<external-path
name="external_storage_root"
path="."/>
</paths>
這里指定了根目錄
與6.0及以下的系統(tǒng)兼容
以上這種通過 FileProvider 形式取得的 Uri 只能在 7.0 以上的設備上使用,在以下的系統(tǒng)回報這個錯誤:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=content://com.graypn.android_common.fileProvider/external_storage_root/szssmartparty.apk typ=application/vnd.android.package-archive flg=0x1 }
所以要有對不同的系統(tǒng)進行不同的處理,最終代碼如下:
/**
* 調(diào)用系統(tǒng)安裝應用
*/
public static boolean install(Context context, File file) {
if (file == null || !file.exists() || !file.isFile()) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri apkUri;
// Android 7.0 以上不支持 file://協(xié)議 需要通過 FileProvider 訪問 sd卡 下面的文件,所以 Uri 需要通過 FileProvider 構造,協(xié)議為 content://
if (Build.VERSION.SDK_INT >= 24) {
// content:// 協(xié)議
apkUri = FileProvider.getUriForFile(context, "com.graypn.android_common.fileProvider", file);
//Granting Temporary Permissions to a URI
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
// file:// 協(xié)議
apkUri = Uri.fromFile(file);
}
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(intent);
return true;
}