您的位置:首页 > 移动开发 > Android开发

android 7.0 download and install apk遇到的问题

2017-01-17 17:08 288 查看

android 7.0 download and install apk遇到的问题

背景:还有十天过年,哈哈,今年的成就就是四川移动项目了。不过,最近android7.0出来以后,同事反馈,他的华为mate9,在下载完更新包以后,无法进入到安装流程,这这这。。。这是什么情况,于是进入到了一天的埋头挖土环节。下面就将这天的经历记录下来,供解决问题的思路和参考。

问题1:先说说下载过程,下载完成后,曾经出现过安装包解析错误的问题。

分析:安装包解析错误,一般原因有:
1,、intent配置有误(可以对照google官方intent参数配置,下面的例子也会给出);
2、下载的安装包缺失或者不完整(可以通过adb shell命令查看安装包是否正常);
3、下载到了错误的路径(安装包如果储存在internal中,会遇到安装包解析错误)。

解决方案:我这里出现安装包解析错误的原因是下载到了internal中(也就是context.getFilesDir()),解决方案就是将下载路径切换到external存储中。这里的external存储可以通过Context.getExternalxxx()和Enviroment.getExternalxxx()两种方式配置,区别在于:Context.getExternalxxx()是context当前app的外部存储,6.0以后不需要授予外部存储权限也能进行读写操作;而Enviroment.getExternalxxx()是整个操作系统环境的外部存储,6.0以后,进行读写操作需要授予外部存储权限。以下是异步下载任务的安装包文件创建过程代码片段:
public DownloadTask() {
File tempPath = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "apk");//外部存储路径
if (!tempPath.exists()) {//创建目录
try {
tempPath.mkdir();
} catch (Exception e) {
e.printStackTrace();
}
}
File apkFile = new File(tempPath, "apk.apk");//外部存储路径下的apk文件
if (apkFile.exists()) {//防止文件过多
try {
apkFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}


问题2:上面的文件创建好以后,就是进入到下载过程,下载过程就是根据网络url将apk写入上述文件中,这里就不说明了,不清楚可以google。下面就来说说apk文件下载完毕后的安装,在安装的时候啊,7.0不能启动apk的安装页面。

分析:不行了,不行了,怎么就不行了呢,后来通过google和查询官方文档,找到原因。启动安装页面的思路通常是往intent里面传递action个、flags、uri等参数,然后通过startActivity(Intent)的方式。7.0以前和7.0以后这些参数的配置就不太一样了。
7.0以前,配置action:Intent.setAction(Intent.ACTION_VIEW);配置flags:Intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);配置uri:Intent.setDataAndType(Uri.fromFile(问题1中的apkFile),"application/vnd.android.package-archive")。
7.0以后,配置action:Intent.setAction(Intent.ACTION_INSTALL_PACKAGE);配置flags:Intent.setFlags(Intent.FLAG_GRANT_URI_PERMISSION);配置uri:Intent.setDataAndType(FileProvider.getUriForFile(context, "manifest中的provider,下面的例子会讲到",
问题1中的apkFile),"application/vnd.android.package-archive")。

解决方案:android7.0以前,下面的例子涉及较少,不过完全够用,这里重点讲android7.0以后,正确启动apk安装页面的3个姿势,姿势不对,可能无法安装可能抛出如FileUriExposedException的异常(所有的姿势,都是依据google android7.0新玩儿法api:7.0Changes 和 FileProvider)。
1、在工程的res目录下,创建xml目录,并在xml目录中,创建file_paths.xml文件:作用是存放uri需要提供的文件信息。
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path        //对应的是Context.getExternalCacheDir()
name="apk"		//名字,传递给uri的,可以随意
path="Download/apk/" 	//文件路径,填写上面问题1中的tempPath路径
/>
</paths>

2、在manifest的application中,创建android.support.v4.content.FileProvider:作用是以provider的形式,提供uri所需的apk文件信息。
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.xxx.xxx.fileprovider"<!--com.xxx.xxx为项目包名-->
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3、启动apk安装页面。
Intent intent = new Intent();
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//7.0启动姿势
//com.xxx.xxx.fileprovider为上述manifest中provider所配置相同;apkFile为问题1中的外部存储apk文件
uri = FileProvider.getUriForFile(context, "com.xxx.xxx.fileprovider", apkFile);

intent.setAction(Intent.ACTION_INSTALL_PACKAGE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//7.0以后,系统要求授予临时uri读取权限,安装完毕以后,系统会自动收回权限,次过程没有用户交互} else {//7.0以下启动姿势 uri = Uri.fromFile(apkFile); intent.setAction(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}intent.setDataAndType(uri,
"application/vnd.android.package-archive");context.startActivity(intent);


当然,详细的姿势,可以参考google官网。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐