DownloadManager实现下载、安装更新app功能
一款app必不可少的功能,就是自动检测版本实现下载、安装更新到最新版,除非就打算做一版。
在此我们跳过检测只说下载、更新。我这边是使用DownloadManager封装了一套,在此分享一下。DownloadManager有两个很明显的好处:对于断点续传功能支持很好和当用户切换不同的应用以后下载需可以在后台很好的继续进行。比我们自己实现省了不少事。
简单说一下实现这个业务的方案步棸,必备条件无非是:0、设置下载路径;1、下载;2、监听下载完成更新;3、覆盖安装。
一、抽象为业务接口IUpdateBiz ,如下:
````
public interface IUpdateBiz {
long downLoad();
void install();
void update(long downloadId);
File getSaveFile();
}
````
二、针对DownloadManager封装一个自己的
DownLoadUtil实现下载
````
public class DownLoadUtil {
static DownloadManager manager;
/**
* @param
*loadUrl 下载地址
*@param
* saveFile 存储位置
*@param
* title 下载进度通知上部描述文字
* @param
* desc 下载进度通知上部描述文字
* */
public static long downLoad(String loadUrl, File saveFile,String title, String desc, Context context){
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(loadUrl));
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle(title);
request.setDescription(desc);
request.setDestinationUri(Uri.fromFile(saveFile));
manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long downloadId = manager.enqueue(request);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
return downloadId;
}
/**
* @param
* downloadId 方法downLoad(...)的返回值
* @param
* object 根据需求自行处理
*
* */
public static int loadStatus(long downloadId, Object object){
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor c = manager.query(query);
int status = 0;
if(c.moveToFirst()) {
status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
LogUtil.log("DownLoadUtil", Log.ERROR, "====status===="+status);
switch(status) {
case DownloadManager.STATUS_PAUSED:
LogUtil.log("DownLoadUtil", Log.ERROR, "====STATUS_PAUSED====");
case DownloadManager.STATUS_PENDING:
LogUtil.log("DownLoadUtil", Log.ERROR, "====STATUS_PENDING====");
case DownloadManager.STATUS_RUNNING:
//正在下载,不做任何事情
LogUtil.log("DownLoadUtil", Log.ERROR, "====STATUS_RUNNING====");
break;
case DownloadManager.STATUS_SUCCESSFUL:
//完成
operSucc(object);
ToastUtil.showToast("下载完成");
LogUtil.log("DownLoadUtil", Log.ERROR, "====下载完成====");
break;
case DownloadManager.STATUS_FAILED:
LogUtil.log("DownLoadUtil", Log.ERROR, "====STATUS_FAILED====");
ToastUtil.showToast("下载失败");
break;
}
}
return status;
}
private static void operSucc(Object object){
if(object instanceof UpdateBiz) ((UpdateBiz) object).install();
}
public static int getDownloadProgress(long downloadId , File downFile){
int progress = 0;
long downSize = 0;
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor c = manager.query(query);
Log.i("MainActivity",downFile.toString());
if (c != null && c.moveToFirst()) {
//此处直接查询文件大小
downSize = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//获取文件下载总大小
long fileTotalSize = c.getLong(c.getColumnIndex(
DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
c.close();
Log.w("MainActivity", "downloaded size: " + downSize);
Log.w("MainActivity", "total size: " + fileTotalSize);
if (fileTotalSize != 0) {
progress = (int) (downSize * 100 / fileTotalSize);
}
}
return progress;
}
/**
* 获取指定文件大小
*
* @param
* @return
* @throws Exception
*/
private static long getFileSize(File file) throws Exception {
long size = 0;
if (file.exists()) {
FileInputStream fis = null;
fis = new FileInputStream(file);
size = fis.available();
} else {
file.createNewFile();
Log.e("获取文件大小", "文件不存在!");
}
return size;
}
}
````
三、UpdateBiz实现一中的业务接口IUpdateBiz
````
public class UpdateBiz implements IUpdateBiz{
private File saveFile;
private Context context;
private String loadUrl;
public UpdateBiz(Context context){
this.context = context;
loadUrl = SharedPrefHelper.getInstance().getApkUrl();
makeSaveFile();
}
@Override
public long downLoad() {
ToastUtil.showToast("安装包下载开始");
return DownLoadUtil.downLoad(loadUrl, saveFile, "xx安装包", "xx.apk", context);
}
@Override
public void update(long downloadId) {
int status = DownLoadUtil.loadStatus(downloadId, this);
}
@Override
public void install() {
LogUtil.log("UpdateBiz", Log.ERROR, saveFile.exists() + "=======install=======");
if (!saveFile.exists()) {
return;
}
// 通过Intent安装APK文件
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + saveFile.toString()), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
context.stopService(new Intent(context, UpdateServise.class));
}
private void makeSaveFile(){
// 获得存储卡的路径
String sdpath = Environment.getExternalStorageDirectory() + "/";
String mSavePath = sdpath + "download";
File file = new File(mSavePath);
// 判断文件目录是否存在
if (!file.exists()) {
file.mkdir();
}
saveFile = new File(mSavePath, "xx.apk");
if(saveFile.exists())
saveFile.delete();
}
@Override
public File getSaveFile(){return saveFile;}
}
````
四、启动自己的下载service调用UpdateBiz中业务方法实现下载,更新以及进度监听,安装更新。
````
public class UpdateServise extends Service{
//private UpdateReceiver updateReceiver;
private IUpdateBiz updateBiz;
private long downloadId;
private ProgressDialog mProgress;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public ScheduledExecutorService scheduledExecutorService;
public Future future;
//接受下载进度,在自己的activity里接收广播实现进度更新
public Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what){
case 0x011:
int progress = DownLoadUtil.getDownloadProgress(downloadId,updateBiz.getSaveFile());
Intent intent = new Intent("com.test.progress");
intent.putExtra("progress",progress);
sendBroadcast(intent);
if(progress == 100){
future.cancel(true);
}
break;
}
return true;
}
});
@Override
public void onCreate() {
super.onCreate();
updateBiz = new UpdateBiz(this);
//注册下载状态广播接受者
registerReceiver(updateReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
downloadId = updateBiz.downLoad();
//每隔100ms获取一下下载进度
scheduledExecutorService = Executors.newScheduledThreadPool(1);
future = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
Message msg = mHandler.obtainMessage();
msg.what = 0x011;
mHandler.sendMessage(msg);
}
},0,100, TimeUnit.MILLISECONDS);
//开始下载任务
DownLoadUtil.loadStatus(downloadId, null);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtil.log("UpdateServise", Log.ERROR, "===onDestroy=====onDestroy====onDestroy===");
if(updateReceiver !=null)
unregisterReceiver(updateReceiver);
if (future != null && !future.isCancelled())
future.cancel(true);
if (scheduledExecutorService != null &&
!scheduledExecutorService.isShutdown())
scheduledExecutorService.shutdown();
}
//这个广播接收者只能这么实现,不能继承BroadcastReceiver再实现
private BroadcastReceiver updateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
LogUtil.log("UpdateServise", Log.ERROR, "===downloadId=====onReceive====downloadId===" + downloadId);
//接收到下载完成的广播开始更新
updateBiz.update(downloadId);
}
};
}
````