Android通过DownloadManager实现App的版本更新功能
来源:互联网 发布:韩顺平mysql基础视频 编辑:程序博客网 时间:2024/05/17 23:58
1.DownloadManager介绍
DownloadManger是android 2.3(api level 9)开始 提供的用于优化处理长时间的下载操作。DownloadManager 处理Http/Https连接并监控连接中的状态变化及系统重启来确保每一个下载任务顺利完成。大多数涉及到下载的情况中使用DownloadManager都是很好的选择,尤其是后台继续下载,下载状态回调,断点续传,下载环境设置,下载文件的操作等方面,支持的很好。
DownloadManager是系统开放给第三方应用使用的类,包含两个静态内部类DownloadManager.Query和DownloadManager.Request。DownloadManager.Request用来请求一个下载,DownloadManager.Query用来查询下载信息,具体接口信息可参看最后的api说明。
public long enqueue(Request request)执行下载,返回downloadId,downloadId可用于后面查询下载信息。若网络不满足条件、Sdcard挂载中、超过最大并发数等异常会等待下载,正常则直接下载。
int remove(long… ids) 删除下载,若下载中取消下载。会同时删除下载文件和记录。
Cursor query(Query query) 查询下载信息。
getMaxBytesOverMobile(Context context) 返回移动网络下载的最大值
rename(Context context, long id, String displayName) 重命名已下载项的名字
getRecommendedMaxBytesOverMobile(Context context) 获取建议的移动网络下载的大小
其它:通过查看代码我们可以发现还有个CursorTranslator私有静态内部类。这个类主要对Query做了一层代理。将DownloadProvider和DownloadManager之间做个映射。将DownloadProvider中的十几种状态对应到了DownloadManager中的五种状态,DownloadProvider中的失败、暂停原因转换为了DownloadManager的原因。
3.DownloadManager实现下载代码
3.1下载需要的权限
package com.tt.travel_and.Util;import android.app.DownloadManager;import android.content.Context;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.os.Process;/** * Created by Summer on 2017/9/8. */public class DownLoadRunnable implements Runnable { private String url; private Handler handler; private Context mContext; private long requestId; public DownLoadRunnable(Context context, String url, Handler handler) { this.mContext = context; this.url = url; this.handler = handler; } @Override public void run() { //设置线程优先级为后台,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); startDownload(); } private long startDownload() { //获得DownloadManager对象 DownloadManager downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); //获得下载id,这是下载任务生成时的唯一id,可通过此id获得下载信息 requestId = downloadManager.enqueue(CreateRequest(url)); //查询下载信息方法 queryDownloadProgress(requestId, downloadManager); return requestId; } private void queryDownloadProgress(long requestId, DownloadManager downloadManager) { DownloadManager.Query query = new DownloadManager.Query(); //根据任务编号id查询下载任务信息 query.setFilterById(requestId); try { boolean isGoging = true; while (isGoging) { Cursor cursor = downloadManager.query(query); if (cursor != null && cursor.moveToFirst()) { //获得下载状态 int state = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); switch (state) { case DownloadManager.STATUS_SUCCESSFUL://下载成功 isGoging = false; Bundle bundle = new Bundle(); bundle.putString("path", downloadManager.getUriForDownloadedFile(requestId).toString()); Message msg = handler.obtainMessage(downloadManager.STATUS_SUCCESSFUL); msg.setData(bundle); msg.sendToTarget();//发送到主线程,更新ui break; case DownloadManager.STATUS_FAILED://下载失败 isGoging = false; handler.obtainMessage(downloadManager.STATUS_FAILED).sendToTarget();//发送到主线程,更新ui break; case DownloadManager.STATUS_RUNNING://下载中 /** * 计算下载下载率; */ int totalSize = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); int currentSize = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); int progress = (int) (((float) currentSize) / ((float) totalSize) * 100); handler.obtainMessage(downloadManager.STATUS_RUNNING, progress).sendToTarget();//发送到主线程,更新ui break; case DownloadManager.STATUS_PAUSED://下载停止 handler.obtainMessage(DownloadManager.STATUS_PAUSED).sendToTarget(); break; case DownloadManager.STATUS_PENDING://准备下载 handler.obtainMessage(DownloadManager.STATUS_PENDING).sendToTarget(); break; } } if (cursor != null) { cursor.close(); } } } catch (Exception e) { e.printStackTrace(); } } private DownloadManager.Request CreateRequest(String url) { if(url==null || url.equals("")){ return null; } DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);// 隐藏notification request.setAllowedNetworkTypes(request.NETWORK_WIFI);//设置下载网络环境为wifi request.setTitle("天津出行版本更新"); request.setDescription("正在下载"); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "/tjcx/tianjintrek.apk");//指定apk缓存路径,默认是在SD卡中的Download文件夹 return request; }}
Handler handler = new Handler() { @Override public void handleMessage(final Message msg) { switch (msg.what) { case DownloadManager.STATUS_SUCCESSFUL://下载成功 runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "下载任务已经完成!", Toast.LENGTH_SHORT).show(); DownloadFinished();//下载完成安装apk } }); break; case DownloadManager.STATUS_RUNNING://下载中 final int progress = (int) msg.obj; runOnUiThread(new Runnable() { @Override public void run() { upload_progress.setProgress(progress); tv_currentprogress.setText(progress + "%"); if(progress==100){ dialog_update.dismiss(); } } }); break; case DownloadManager.STATUS_FAILED://下载失败// canceledDialog(); break; case DownloadManager.STATUS_PENDING://准备下载// showDialog(); break; } } };
/** * 下载完成安装apk */ private void DownloadFinished(){ File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath() + "/tjcx/tianjintrek.apk"); if (mFile.getName().endsWith(".apk")) { Intent install = new Intent(); install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); install.setAction(Intent.ACTION_VIEW); if (24 > Build.VERSION.SDK_INT) { install.setDataAndType(Uri.fromFile(mFile), "application/vnd.android.package-archive"); } else { Uri apkUri = FileProvider.getUriForFile(MainActivity.this, "com.tt.travel_and.fileprovider", mFile); install.setDataAndType(apkUri, "application/vnd.android.package-archive"); install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } startActivity(install); LocationApplication.setUserInfo(null, null, null); } }
/** * 自定义的更新提示dialog */ private void showUpdateAppAlertDialogs() { LayoutInflater inflater = LayoutInflater.from(MainActivity.this); AutoLinearLayout layout = (AutoLinearLayout) inflater.inflate(R.layout.updateapp_dialogs, null); txt_title = (TextView) layout.findViewById(R.id.txt_title); txt_title.setText(getResources().getString(R.string.discovernewversion) + version_name); txt_msg = (TextView) layout.findViewById(R.id.txt_msg); txt_msg.setText(getResources().getString(R.string.app_name_cn)+version_name+getResources().getString(R.string.update_appcontent)); // txt_msg.setText(version_name); rl_update_unmust = (AutoLinearLayout) layout.findViewById(R.id.rl_update_unmust); rl_updates = (AutoRelativeLayout) layout.findViewById(R.id.rl_update); upload_progress = (ProgressBar) layout.findViewById(R.id.upload_progress);//更新进度条 tv_currentprogress = (TextView) layout.findViewById(R.id.tv_currentprogress); //显示实时更新进度 Button btn_updateapp = (Button) layout.findViewById(R.id.btn_updateapp); Button btn_updateappcancel = (Button) layout.findViewById(R.id.btn_updateappcancel); btn_updateappcancel.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) { dialog_update.dismiss(); } });
//点击更新按钮 btn_updateapp.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {// appupdate(); rl_update_unmust.setVisibility(View.GONE); rl_updates.setVisibility(View.VISIBLE); download();//apk下载方法 } }); dialog_update = new AlertDialog.Builder(MainActivity.this, R.style.NoExitAnimDialog).create(); dialog_update.setCanceledOnTouchOutside(false);//dialog弹出后会点击屏幕,dialog不消失;点击物理返回键dialog消失 dialog_update.show(); dialog_update.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); dialog_update.getWindow().setContentView(layout); dialog_update.getWindow().setBackgroundDrawableResource(R.color.transparent); }private void download() {//android6.0以后要动态申请权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(MainActivity.this, "android.permission.WRITE_EXTERNAL_STORAGE")) {//判断当前系统的SDK版本是否大于23 verifyStoragePermissions(MainActivity.this);//先去动态申请权限 通过用户同意权限 则开启下载线程 return; } /** * 更新的时候先检查安装包在sd卡中是否存在,如果存在则直接安装,不存在开启下载线程进行下载 */ File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath() + "/tjcx/tianjintrek.apk"); if (mFile.exists()) {//安装包存在,直接安装 dialog_update.dismiss(); DownloadFinished();//下载完成安装apk }else{//下载apk //最好是用单线程池,或者intentService取代 new Thread(new DownLoadRunnable(this, url, handler)).start();//url换成你apk的下载地址就可以了 }}/** * 运行时权限处理 * 用户选择允许或拒绝后,会回调onRequestPermissionsResult方法, 该方法类似于onActivityResult * @param requestCode * @param permissions * @param grantResults */
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {// Log.i("CMCC", "权限被允许"); /** * 更新的时候先检查安装包在sd卡中是否存在,如果存在则直接安装,不存在开启下载线程进行下载 */ File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath() + "/tjcx/tianjintrek.apk"); if (mFile.exists()) {//安装包存在,直接安装 dialog_update.dismiss(); DownloadFinished(); }else{//下载apk //最好是用单线程池,或者intentService取代 new Thread(new DownLoadRunnable(this, url, handler)).start(); } } else { finish(); Toast.makeText(this, "同意权限后才能进行更新,请手动进入设置打开手机读取sd卡权限", Toast.LENGTH_LONG).show(); } }
package com.tt.travel_and.service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.Environment;import android.util.Log;import android.widget.Toast;import java.io.File;/** * Created by Summer on 2017/10/10. */public class InitApkBroadCastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.e("-------------",intent.getData().getSchemeSpecificPart()); if (context.getPackageName().equals(intent.getData().getSchemeSpecificPart())) { File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath() + "/tjcx/tianjintrek.apk"); if (mFile.exists()) { mFile.delete();//app替换成功以后直接删除安装包 Toast.makeText(context, "已删除安装包", Toast.LENGTH_SHORT).show(); } } }}
4.3在AndroidManifest中注册广播
<receiver android:name=".service.InitApkBroadCastReceiver"> <intent-filter> <!-- 一个新版本的应用安装到设备,替换之前已经存在的版本 替换时会先收到卸载的再收到替换的, 替换自身也能收到--> <action android:name="android.intent.action.PACKAGE_REPLACED" /> <data android:scheme="package" /> </intent-filter></receiver>好了到这通过DownloadManager实现app的版本更新和apk安装完成后删除安装包都已经说完了,希望对大家的学习和工作有所帮助。
- Android通过DownloadManager实现App的版本更新功能
- DownloadManager实现下载、安装更新app功能
- 使用android自带的DownloadManager来实现版本更新
- Android使用DownloadManager实现版本更新
- Android app“版本更新”功能的前后端实现
- Android版本更新使用DownloadManager
- Android 通过DownloadManager实现自动更新的demo
- android中DownloadManager实现版本更新,监听下载进度实例
- Android DownloadManager 系统下载器实现APP升级功能
- Android 使用DownloadManager进行版本更新的完整方案
- Android 使用DownloadManager进行版本更新的完整方案
- Android 版本更新功能的实现
- Android App 版本更新实现
- 安卓开发实战之app之版本更新升级(DownloadManager和http下载)完整实现
- 安卓开发实战之app之版本更新(DownloadManager和http下载)完整实现
- Android使用DownLoadManager(下载管理器)更新版本
- Android 开发中 app版本更新功能
- Android使用AsyncTask实现可以断点续传的DownloadManager功能
- Angular2如何使用第三方类库(如:jQuery)
- OA需求设计
- linux下的tuxedo开发实例
- 正则表达式中的数量词概念
- 未结束的字符串常量
- Android通过DownloadManager实现App的版本更新功能
- VS2013 断点总是乱跳
- 猫眼电影TOP100爬取
- LeetCode Maximum Subarray Maximum Product Subarray DP问题
- 第七单元
- SQL入门的问题(1)
- JAVA代理模式
- 常用权限和依赖
- mysql 5.7 binary 二进制版本安装 for linux 7