在Android7.0中引入了“私有目录访问受限”,使用FileProvider解决了问题,但是安装应用时解析包出错
让我们检查一下代码
private void installApk(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
apkUri = FileProvider.getUriForFile(mContext
, "项目包名.FileProvider"
, file);
} else {
apkUri = Uri.fromFile(file);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
mContext.startActivity(intent);
}
因为这个问题只出现在Android7.0,所以很容易认为可能是FileProvider引起的,但是查了半天,还是找不到是什么原因造成的。仔细对比7.0之前的安装代码,发现将intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)移到前面就可以正常安装了。
private void installApk(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
// 将此段代码移到此,可正常安装
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
apkUri = FileProvider.getUriForFile(mContext
, "项目包名.FileProvider"
, file);
} else {
apkUri = Uri.fromFile(file);
}
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
mContext.startActivity(intent);
}
具体原因
Android 7.0 通过 FileProvider 共享文件。因为exported为false,需要给目标应用授予临时权限,所以会设置intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
添加此权限后,intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 替换了添加的权限解析程序包出错,所以仍然没有授予权限。然后将intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)操作放在addFlags()之前或者替换成intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
这里要小心
setFlags():为 Intent 设置特殊标志,这将覆盖 Intent 已经设置的所有标志。
addFlags():为intent添加特殊标志,不会被覆盖,只会追加。
添加问题
在华为安卓8.0手机上,遇到上述方法无法解决的包解析错误。想起各种排查问题的方法解析程序包出错,分析猜测,锁屏时安装APK的服务可能处于休眠状态。不可用状态,导致intent.addFlags()临时授予的权限失效。
解决问题的改进代码如下
private void installApk(File file) {
try{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
apkUri = FileProvider.getUriForFile(mContext
, "项目包名.FileProvider"
, file);
} else {
apkUri = Uri.fromFile(file);
}
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
// 查询所有符合 intent 跳转目标应用类型的应用,注意此方法必须放置在 setDataAndType 方法之后
List resolveLists = mContext.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
// 然后全部授权
for (ResolveInfo resolveInfo : resolveLists){
String packageName = resolveInfo.activityInfo.packageName;
mContext.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
mContext.startActivity(intent);
}catch (Exception e){
e.printStackTrace();
}
}
请登录后发表评论
注册
社交帐号登录