android apk 安装目录成功,记录一次解决安装 Apk 兼容性问题

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

问题描述现象

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

场景

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

解决之前安装Apk的方法首先在AndroidManifest中声明fileProvider

android:name="android.support.v4.content.FileProvider"

android:authorities="${applicationId}.fileprovider"

android:exported="false"

android:grantUriPermissions="true">

android:name="android.support.FILE_PROVIDER_PATHS"

android:resource="@xml/file_path"/>

provider属性说明

属性

说明

name

android V4 包中的类FileProvider

authorities

你的文件的Uri的域名一般以包名.fileprovider的格式,防止重名

exported

设置不允许导出,我们的FileProvider应该是私有的

grantUriPermissions

允许获取文件的临时访问权限

resourse

设置FileProvider访问的文件路径

res包下创建file_path.xml

name="external_path"

path="test"/>

name="internal_path"

path="test"/>

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

path 说明

对应的是:Context.getFileDir()的路径地址

对应路径 :Context.getFileDir()+ "/${path}/"

得到路径 :content://${applicationId}/&{name}/

对应路径 :Context.getCacheFir()+ "/${path}/"

得到路径 :content://${applicationId}/&{name}/

对应路径 :Environment.getExternalStorageDirectory()+ "/${path}/"

得到路径 :content://${applicationId}/&{name}/

对应路径 :Context.getExternalStorageDirectory()+ "/${path}/"

得到路径 :content://${applicationId}/&{name}/

对应路径: Context.getExternalCacheDir()+ "/${path}/"

得到路径: content:/ /${applicationId}/&{name}/

举个例子说明:

path做如下声明

File imagePath = newFile(Context.getFilesDir(), "images");

File newFile = newFile(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版本兼容问题)publicstaticvoidinstallApk(Context context,File apkFile){

try{

Intent intent = newIntent(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系统需要声明权限

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

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

java.lang.SecurityException: Permission Denial:

opening provider android.support.v4.content.FileProvider fromProcessRecord{cc3ad2316425:

com.android.packageinstaller/u0a21} (pid= 16425, uid= 10021) that isnotexported fromuid 10340

543a351bccbc335fac12f7241c653395.png

懵逼.jpg 问题定位

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

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

改进后的代码public staticvoidinstallApk(Context context,File apkFile){

try{

Intent intent = newIntent(Intent.ACTION_VIEW);

UriapkUri = 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 resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

//然后全部授权

for(ResolveInfo resolveInfo : resInfoList) {

StringpackageName = 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();

}

}

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

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值