实现 DownloadManager 下载完 apk 自动提示安装的功能
运行环境
- Android 5.1.1, API 22
解决方案
- 下载新版本的
apk
1 2 3 4 5 6 7
public void downloadNewVersion() { mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); // apkDownloadUrl 是 apk 的下载地址 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkDownloadUrl)); // 获取下载队列 id enqueueId = mDownloadManager.enqueue(request); }
- 注册接收下载完成的广播
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { long downloadCompletedId = intent.getLongExtra( DownloadManager.EXTRA_DOWNLOAD_ID, 0); // 检查是否是自己的下载队列 id, 有可能是其他应用的 if (enqueueId != downloadCompletedId) { return; } DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(enqueueId); Cursor c = mDownloadManager.query(query); if (c.moveToFirst()) { int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); // 下载失败也会返回这个广播,所以要判断下是否真的下载成功 if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) { // 获取下载好的 apk 路径 String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME)); // 提示用户安装 promptInstall(Uri.parse("file://" + uriString)); } } } }; // 注册广播, 设置只接受下载完成的广播 registerReceiver(receiver, new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE));
- 取消注册广播, 不取消注册的话, 调用
recreate
时会报Are you missing a call to unregisterReceiver()?
错误1 2 3 4 5 6
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mBroadcastReceiver); }
- 提示用户安装
1 2 3 4 5 6 7
private void promptInstall(Uri data) { Intent promptInstall = new Intent(Intent.ACTION_VIEW) .setDataAndType(data, "application/vnd.android.package-archive"); // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(promptInstall); }
就是这样,运行 app 看下效果吧
总结
坑比较多,花了3天时间才完全实现这个效果 1个坑是必须使用setDataAndType()
,而不能单独使用setData()
和setType()
另外一个坑是getUriForDownloadedFile
现在返回的是content://
这种格式的链接了,无法用于启动intent
最后一个坑是intent
必须设置FLAG_ACTIVITY_NEW_TASK
, 否则安装完成后无法正常打开app
常见问题
提示解析程序包时出现问题
答
mDownloadManager.getUriForDownloadedFile(enqueueId)
返回的Uri
是这种格式的content://downloads/my_downloads/83
, 这种格式的Uri
启动intent
会报解析程序包时出现问题
No Activity found to handle Intent
No Activity found to handle Intent { act=android.intent.action.VIEW dat=/storage/sdcard/download/demo.apk typ=application/vnd.android.package-archive
答
可能原因1: 有可能是没有权限读取这个文件或者文件路径错误
可能原因2:
1
2
3
4
5
// Intent promptInstall = new Intent(Intent.ACTION_VIEW)
// .setData(data)
// .setType("application/vnd.android.package-archive");
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setDataAndType(data, "application/vnd.android.package-archive");
单独设置data
和type
也会造成这个错误,原因请看http://developer.android.com/reference/android/content/Intent.html#setData(android.net.Uri) 你会发现无论何时你去设置data
或者type
, 另外一个都会自动的变为空, 例如: setData()
会使得type
参数值为空, 如果你想让两者都生效的话只能使用setDataAndType()
提示应用程序未安装
答
有可能是因为APK
签名不一致, 比如之前是debug
版(无签名), 现在你更新安装release
版(有签名), 就会出现这个问题
参考链接
- Android 安卓系统提示应用程序未安装的解决方法
- Android DownloadManager and Media Scanner
- Android: install .apk programmatically
- 为何必须用setDataAndType, 而不能单独设置data和type
- Android DownloadManager Example
- 在应用中更新App版本
- DownloadManager补漏
- 全局接收下载完成的广播
更新纪录
- 2016年3月8日 添加取消注册广播的代码
- 2016年1月22日 发布
Comments powered by Disqus.