公司最近开展一个新的项目,需要加上版本自动更新的功能。在新版本上线时,有公司的外派同事反馈说在更新时,会直接奔溃。通过不断的查找发现,只有在华为部分手机出现了类似的问题(Mate8,P9都会)。这里把问题记录下
分析与解决
1 情形
自动更新使用了系统提供的DownloadManager,当下载完成时,通过广播机制对下载完成事件进行广播,action为DownloadManager.ACTION_DOWNLOAD_COMPLETE
Uri filepath = downloadManager.getUriForDownloadedFile(reference);
if (intent.getAction() == DownloadManager.ACTION_DOWNLOAD_COMPLETE
&& filepath != null) {
Intent intents = new Intent();
intents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intents.setAction("android.intent.action.VIEW");
intents.addCategory("android.intent.category.DEFAULT");
intents.setType("application/vnd.android.package-archive");
intents.setData(filepath);
intents.setDataAndType(filepath,
"application/vnd.android.package-archive");
context.startActivity(intents);
System.exit(0);
}
2 问题
下载文件的uri(即filepath)不为空,但启动安装应用时,会发生奔溃现象
3 猜想
是否因为无法正确识别uri,导致系统奔溃?写了一个例子,直接使用下载文件的绝对路径进行启动,正常使用。
if (intent.getAction() == DownloadManager.ACTION_DOWNLOAD_COMPLETE
&& filepath != null) {
Intent intents = new Intent();
intents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intents.setAction("android.intent.action.VIEW");
intents.addCategory("android.intent.category.DEFAULT");
intents.setType("application/vnd.android.package-archive");
intents.setData(Uri.fromFile(new File(Tool.getFilePathByUri(
context, filepath))));
intents.setDataAndType(Uri.fromFile(new File(Tool.getFilePathByUri(
context, filepath))),
"application/vnd.android.package-archive");
context.startActivity(intents);
System.exit(0);
}
4 验证
调用系统的图片选择,会在onActivityResult中会返回图片的URI,再通过URI去获取图片,也出现了奔溃的情况:华为的部分手机对于URI的兼容有问题
5 总结
因为android开源,国内很多手机厂商会修改系统源码,对系统进行优化等,开发属于自己的一套系统UI(不能算系统,只是在android的基础上进行二次开发)。华为作为国内前几位的手机开发商也不例外,开发了自己的EMUI系统,这难免会对系统进行调整和修改。鉴于这种情况,我们需要对应用进行多设备的兼容性测试,提高应用的稳定性。
URI与路径的转换
为了解决上边出现的问题,需要setData传入下载文件的路径,这就需要将URI转换成路径,这里也给出相应的方法
public static String getFilePathByUri(final Context context, final Uri uri) {
if (null == uri)
return null;
final String scheme = uri.getScheme();
String data = null;
if (scheme == null)
data = uri.getPath();
else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
data = uri.getPath();
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
Cursor cursor = context.getContentResolver().query(uri,
new String[] { ImageColumns.DATA }, null, null, null);
if (null != cursor) {
if (cursor.moveToFirst()) {
int index = cursor.getColumnIndex(ImageColumns.DATA);
if (index > -1) {
data = cursor.getString(index);
}
}
cursor.close();
}
}
return data;
}