封面图还是要有的
之前使用Intent
安装APK文件,使用下面的代码可以直接调起安装界面。
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才发现app在Android 8.0的手机上无法正常安装,一查才知道从Android N(也就是Android API 24)开始直接执行上面的代码会报android.os.FileUriExposedException
异常,需要使用FileProvider
来处理对Content URI读取的临时授权问题。直接上解决方案
首先,需要在AndroidManifest.xml
文件中的<application>
标签中定义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>
标签中的android:authorities
为设置授权的URI,一般都是授权自己app包名下的fileprovider
,也就是应用包名.fileprovider
;而android:exported
属性为false
则表示该FileProvider
不是需要是公共的。另外,android:grantUriPermissions
属性为true
表示允许给文件临时访问权限。
然后,在res/xml
目录下定义一个apk_path.xml
文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="apk_path"
path="."/>
</paths>
<paths>
中必须有子元素,这里使用<external-path>
标签对应的是使用Environment.getExternalStorageDirectory()
路径,name
属性则是名称,path
则是表示临时授权的子目录路径(不是单个文件),使用.
表示所有路径,这个可以根据需求添加。
将定义好的apk_path.xml
文件通过<meta-data>
添加到之前在AndroidManifest.xml
文件中定义的<provider>
中,将<meta-data>
标签的android:resource
属性设置为@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);
//第二个参数需要与<provider>标签中的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);
}