记录一次解决安装 Apk 兼容性问题-阿里云开发者社区

开发者社区> 技术小能手> 正文

记录一次解决安装 Apk 兼容性问题

简介:
+关注继续查看

问题描述

现象

代码执行安装Apk,出现系统弹框解析错误,解析包时出现错误

场景

在华为P20 Android 8.0 手机上,下载Apk并使用通知栏进度条显示,开启应用锁屏通知权限,下载过程在锁屏情况下进行,下载完成后自动执行安装Apk,在解锁后出现系统弹框,解析包出现错误。

解决之前安装Apk的方法

首先在AndroidManifest中声明fileProvider


<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>

provider属性说明

属性 说明
name android V4 包中的类FileProvider
authorities 你的文件的Uri的域名一般以包名.fileprovider的格式,防止重名
exported 设置不允许导出,我们的FileProvider应该是私有的
grantUriPermissions 允许获取文件的临时访问权限
resourse 设置FileProvider访问的文件路径

res包下创建file_path.xml


<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_path"
path="test" />

<cache-path
name="internal_path"
path="test" />

这里可以创建很多个paths,但是每个paths的name不能一样


</paths>

path 说明


<files-path name="*name*" path="*path*" /> 对应的是:Context.getFileDir()的路径地址

对应路径:Context.getFileDir()+"/${path}/"
得到路径:content://${applicationId}/&{name}/

<cache-path name="*name*" path="*path*" />
对应路径:Context.getCacheFir()+"/${path}/"
得到路径:content://${applicationId}/&{name}/


<external-path name="*name*" path="*path*" />
对应路径:Environment.getExternalStorageDirectory()+"/${path}/"
得到路径:content://${applicationId}/&{name}/

<external-files-path name="*name*" path="*path*" />
对应路径:Context.getExternalStorageDirectory()+"/${path}/"
得到路径:content://${applicationId}/&{name}/

<external-cache-path name="*name*" path="*path*" />
对应路径: Context.getExternalCacheDir()+"/${path}/"
得到路径:content://${applicationId}/&{name}/

举个例子说明:


path做如下声明
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
</paths>

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);

contentUri值为:content://com.mydomain.fileprovider/my_images/default_image.jpg
安装apk的方法(7.0版本兼容问题)

public static void installApk(Context context,File apkFile){
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri apkUri = null;
//判断版本是否是 7.0 及 7.0 以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
//添加对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
apkUri = Uri.fromFile(apkFile);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apkUri,
"application/vnd.android.package-archive");
context.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}

}
Android 8.0系统需要声明权限
 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGE" />

OK,以上就是大家普遍解决7.0,以及8.0版本兼容问题的方法。

但是,在上文描述的场景中依然报出了错误:


java.lang.SecurityException: Permission Denial:
opening provider android.support.v4.content.FileProvider from ProcessRecord{cc3ad2316425:
com.android.packageinstaller/u0a21} (pid=16425, uid=10021) that is not exported from uid 10340

f5b58a505817b7e2806a7e8ea6c028bbf92458ea

懵逼.jpg
问题定位

经过短暂的懵逼后,开始通过各种方式,探索问题的原因。

根据系统log分析,猜测在锁屏时,用于安装Apk的service处于休眠或者不可用的状态,导致通过intent.addflags方式赋予的临时权限失效了。于是,再次仔细看了官方文档后,发现还有一个方法,可以生成权限且在主动调用方法或者手机重启后才会失效。

改进后的代码


public static void installApk(Context context,File apkFile){
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri apkUri = null;
//判断版本是否是 7.0 及 7.0 以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
//添加对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
apkUri = Uri.fromFile(apkFile);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apkUri,
"application/vnd.android.package-archive");
//查询所有符合 intent 跳转目标应用类型的应用,注意此方法必须放置setDataAndType的方法之后
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
//然后全部授权
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
context.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}

}

再次尝试,此问题再没有出现。


原文发布时间为:2018-11-9

本文作者:bear~

本文来自云栖社区合作伙伴“安卓巴士Android开发者门户”,了解相关信息可以关注“安卓巴士Android开发者门户”。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【PHP】编译安装 PHP5.6.13遇到问题以及解决方案
问题 在执行 ./configure的时候报错 configure: error: xml2-config not found. Please check your libxml2 installation.
845 0
linux中PHP7.*源码安装过程中遇到的问题及解决办法
准备搭建一个轻社区娱乐一下,但轻社区要求的PHP版本必须>6.5,而linux自带PHP大都5.*,所以必须要在网上找源码安装,然后,我便找了一个安装教程(链接地址:https://blog.
1072 0
mysql 7下载安装及问题解决
mysql 7安装及问题解决 一、mysql下载 下载地址:https://www.mysql.com/downloads/ Community (GPL) Downloads MySQL Community Server (GPL) Windows (x86, 64-bit), ZIP Archive No thanks, just start my download.
722 0
基于Knox登录Yarn UI查看SparkStreaming作业兼容性问题说明
问题背景 1.登录EMR集群节点,运行SparkStreaming示例,如下所示(不同版本EMR集群spark-examples_xxx.jar的路径略有差异): [root@emr-header-1 ~]# spark-submit --class org.
1537 0
fbh
前端页面兼容性问题学习
2018.6.16 端午节开始笔记 说道前端页面兼容问题,首先应该了解,通过同一网站怎么判断打开用户是手机端还是pc端,这是前端页面兼容问题前提。
885 0
使用DotNetNuke(DNN) Startkit 4.7(及以上版本)安装无法完成问题的解决方法
最近决定使用DNN Startkit 做些开发,却发现下载DNN 4.8.2 Startkit安装后,生成的网站总是无法完成安装,一到数据库安装那里就停下来,只有进度条滚动,不执行安装的Script。 如图: 几经周折,最终发现自己犯了了一个很愚蠢的错误-没有仔细阅读说明。
658 0
解决JDk1.6无法安装得问题
最近得JDK1.6测试版下载回来后总是安装不了, 一双击安装文件来,就会提示“无法应用转换程序“,其实这是 JDK1.6 开发中得一个下BUG,这个BUG将再B94中得到修正。
528 0
+关注
技术小能手
云栖运营小编~
5974
文章
9
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载