前段时间,公司有个需求,要求每次用户打开app的时候,请求后台的接口,查看是否有最新版本的包,如果有更新,则去后台偷偷的下载最新版本的apk,考虑到用户流量,要求下载apk必须是在wifi环境下下载,基于此需求,主要有如下几个方面的考虑:
一、app首页请求接口,根据后台返回的最新版本号,以及数据库存的版本号,判断是否需要开始下载,还是接着上次下载
二、下载管理器:如果需要下载,则开启service,service中开启一个线程,让线程去下载apk,注意:如果wifi断了,一定要关闭线程,关闭service
三、对wifi写个广播接收者,如果wifi断了,这时候应该停止下载,如果wifi又连上了,则继续上次的下载
四、数据库:如果此时wifi断了,然后新版本又下载了一部分了,此时需要暂停下载,将已经下载的部分,包括下载的进度,新版的版本号等信息存入数据库中,基于此考虑,第一条,还需要根据数据库存入的版本号做比对,因为如果本地是1,数据库存的是2,这时候请求接口,发现接口返回是3,则需要更新数据库,并将已经下载的本地文件删除,重新下载
贴部分代码:
一、
//请求是否需要更新,请求后台的接口
requestVersionUpdate();
//后台接口返回
@Override
public voidonDataChanged(UpdateVersion data, NetworkHelper helper) {
if(null!= data) {
intro= data.intro;//更新文案
download_link= data.download_link;//新版本的下载链接
newVersion= data.version_code;//新版本的code
mDao=newThreadDaoImpl(SplashActivity.this);//得到数据库操作对象
threadInfo=mDao.select();//查询数据库里保存的纪录,如果没有,则为空
if(null!=threadInfo) {
dbVersion=threadInfo.getVersioncode();//得到数据库里保存的,上次下载的apk的版本号
}
fileName="/ceshi.apk";
forceInstall= data.force_update;//是否强制用户安装
//当前程序的版本号
intcurrentVersionCode = CommonHelper.getVersionCode(getApplicationContext());
if(newVersion== currentVersionCode) {
//如果有文件,则删除apk所在的文件
File file =newFile(DownloadService.DOWNLOAD_PATH);
if(file.exists()) {
FileUtil.deleteFile(file);
}
}else{
DownloadHelper downloadHelper =newDownloadHelper(SplashActivity.this);
if(dbVersion== -1) {
//通知下载器去下载,并且把纪录插入数据库中
ThreadInfo info =newThreadInfo(0,download_link,0,0,0,newVersion, MySqliteHelper.UNDOWNLOAD,intro, DownloadService.DOWNLOAD_PATH,fileName);
if(!mDao.isExists(newVersion)) {
mDao.insertThread(info);
}
//如果文件已经存在,则删除文件,防止用户已经部分下载了,然后把程序卸载了,后来又重新安装,此时需要将文件删除
File file =newFile(info.getDownloadFile());
if(file.exists()) {
FileUtil.deleteFile(file);
}
downloadHelper.downloadApk(info);
}else if(newVersion>dbVersion) {
//从数据库里查询是否下载过apk,如果有则删除下载的apk文件,并且将dbversion更新为最新的版本号
File file =newFile(threadInfo.getDownloadFile() +threadInfo.getFileName());
Log.i("anru","newVersion > dbVersion:::file:"+ file.toString());
// 路径为文件且不为空则进行删除
if(file.isFile() && file.exists()) {
file.delete();
mDao.deleteThread(dbVersion);
}
//删除之后,去启动下载
//通知下载器去下载
ThreadInfo info =newThreadInfo(0,download_link,0,0,0,newVersion, MySqliteHelper.UNDOWNLOAD,intro, DownloadService.DOWNLOAD_PATH,fileName);
if(!mDao.isExists(newVersion)) {
mDao.insertThread(info);
}
downloadHelper.downloadApk(info);
}else if(newVersion==dbVersion&&dbVersion> currentVersionCode) {
//从数据库里查询是否下载过apk,如果有则删除下载的apk文件,并且将dbversion更新为最新的版本号
File file =newFile(threadInfo.getDownloadFile() +threadInfo.getFileName());
if(threadInfo.getApkstatus() != MySqliteHelper.DOWNLOAD_COM) {
//继续去下载
downloadHelper.downloadApk(threadInfo);
}else if(!MD5Helper.getMD5(file).equals(data.apk_md5)) {//如果md5值不一致,则删除原文件,重新下载
// 路径为文件且不为空则进行删除
if(file.isFile() && file.exists()) {
file.delete();
mDao.deleteThread(dbVersion);
}
//删除之后,去启动下载
//通知下载器去下载
ThreadInfo info =newThreadInfo(0,download_link,0,0,0,newVersion, MySqliteHelper.UNDOWNLOAD,intro, DownloadService.DOWNLOAD_PATH,fileName);
if(!mDao.isExists(newVersion)) {
mDao.insertThread(info);
}
}else{
//提示用户安装
isShowInstall=1;
}
}
}
}
二、下载管理器:
//开启服务
Intent intent =newIntent(context, DownloadService.class);
intent.putExtra("info",info);
DownloadTask.mIsPause=false;
context.startService(intent);
//在服务页面,开启线程
@Override
public intonStartCommand(Intent intent,intflags,intstartId) {
try{
ThreadInfo info = (ThreadInfo) intent.getSerializableExtra("info");
if(info.getApkstatus() != MySqliteHelper.DOWNLOAD_COM) {//如果暂时未下载,去下载
//判断网络状态
if(isWifiAvailable()) {
thread=newInitThread(info);
thread.start();
}
}
}catch(Exception e) {
e.printStackTrace();
Log.i("anru","download kill");
DownloadTask.mIsPause=true;
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
//下载的线程
classDownLoadThread extends Thread {
privateThreadInfo info;
public DownLoadThread(ThreadInfo info) {
this.info= info;
}
@Override
public voidrun() {
Log.i("anru","download开始下载");
Log.i("anru","apkstatus:"+info.getApkstatus());
HttpURLConnection conn =null;
RandomAccessFile raf =null;
InputStream in =null;
try{
URL url =newURL(info.getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setDoInput(true);
conn.setRequestMethod("GET");
// 设置下载位置
int start =info.getStart() +info.getFinished();
conn.setRequestProperty("Range",
"bytes="+ start +"-"+info.getEnd());
// 设置文件写入位置
File file =new File(info.getDownloadFile(),info.getFileName());
raf =new RandomAccessFile(file,"rwd");
raf.seek(start);
//Intent intent = new Intent(DownloadService.ACTION_UPDATE);
finished+=info.getFinished();
// 开始下载
if(conn.getResponseCode() ==206|| conn.getResponseCode() ==200) {//206 Partial Content
// 读取数据
in = conn.getInputStream();
intlen = -1;
byte[] b =new byte[1024*4];
longtime = System.currentTimeMillis();
while((len = in.read(b)) != -1) {
// 写入文件
raf.write(b,0, len);
finished+= len;
Log.i("anru","finished:"+finished);
info.setFinished(finished);
if(finished==info.getEnd()) {
info.setApkstatus(MySqliteHelper.DOWNLOAD_COM);
}else if(finished>0&&finished
info.setApkstatus(MySqliteHelper.DOWNLOAD_UNCOM);
}
mDao.updateThread(info);
// 在下载暂停时,保存下载进度
if(mIsPause) {
Log.i("anru","mIsPause");
return;
}
}
}
}catch(Exception e) {
Log.e("anru","跳出来了");
}finally{
try{
raf.close();
if(null!= in) {
in.close();
}
conn.disconnect();
}catch(Exception e) {
e.printStackTrace();
}
}
}
三、wifi监听器广播
@Override
public void onReceive(Context context, Intent intent) {
//TODO Auto-generated method stub
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {//wifi连接上与否
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
//暂停apk的下载
Intent intent1 =newIntent(context, DownloadService.class);
context.stopService(intent1);
}else if(info.getState().equals(NetworkInfo.State.CONNECTED)) {
//继续去下载
DownloadHelper downloadHelper =newDownloadHelper(context);
ThreadDaoImpl mDao =newThreadDaoImpl(context);
ThreadInfo threadInfo = mDao.select();
downloadHelper.downloadApk(threadInfo);
}
}
}
四、数据库:
public interface ThreadDao {
public void insertThread(ThreadInfo info);
public void updateThread(ThreadInfo info);
public List getThreads(String url);
public boolean isExists(intversionCode);
public ThreadInfo select();
public void deleteThread(intversionCode);
上边代码只挑了一些比较重点的贴了,如果想下载demo,链接:
http://download.csdn.net/detail/forever521_/9510974
网友评论