封面圖還是要有的
之前使用Intent
安裝APK文件,使用下面的代碼可以直接調(diào)起安裝界面夹抗。
public void installAPK(Context context, File apkFile){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
context.startActivity(intent);
}
最近把targetSdkVersion
升級到了26才發(fā)現(xiàn)app在Android 8.0的手機(jī)上無法正常安裝莫秆,一查才知道從Android N(也就是Android API 24)開始直接執(zhí)行上面的代碼會報android.os.FileUriExposedException
異常凭语,需要使用FileProvider
來處理對Content URI讀取的臨時授權(quán)問題。直接上解決方案
首先昆箕,需要在AndroidManifest.xml
文件中的<application>
標(biāo)簽中定義FileProvider
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true"
android:authorities="com.mrtrying.installappdemo.fileprovider">
...
</provider>
...
</application>
注意:這里
<provider>
標(biāo)簽中的android:authorities
為設(shè)置授權(quán)的URI,一般都是授權(quán)自己app包名下的fileprovider
租冠,也就是應(yīng)用包名.fileprovider
鹏倘;而android:exported
屬性為false
則表示該FileProvider
不是需要是公共的。另外顽爹,android:grantUriPermissions
屬性為true
表示允許給文件臨時訪問權(quán)限纤泵。
然后,在res/xml
目錄下定義一個apk_path.xml
文件镜粤,內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="apk_path"
path="."/>
</paths>
<paths>
中必須有子元素捏题,這里使用<external-path>
標(biāo)簽對應(yīng)的是使用Environment.getExternalStorageDirectory()
路徑,name
屬性則是名稱肉渴,path
則是表示臨時授權(quán)的子目錄路徑(不是單個文件)公荧,使用.
表示所有路徑,這個可以根據(jù)需求添加同规。
將定義好的apk_path.xml
文件通過<meta-data>
添加到之前在AndroidManifest.xml
文件中定義的<provider>
中循狰,將<meta-data>
標(biāo)簽的android:resource
屬性設(shè)置為@xml/apk_path
<provider
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true"
android:authorities="com.mrtrying.installappdemo.fileprovider">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/apk_path"/>
</provider>
最后,只需要在代碼中使用FileProvider
來獲取URI就大功告成了
public void installAPK(Context context, File apkFile){
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//第二個參數(shù)需要與<provider>標(biāo)簽中的android:authorities屬性相同
uri = FileProvider.getUriForFile(this,"com.mrtrying.installappdemo.fileProvider",apkFile);
}else{
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
uri = Uri.fromFile(apkFile);
}
intent.setDataAndType(uri ,"application/vnd.android.package-archive");
context.startActivity(intent);
}