前段時(shí)間,公司有個(gè)需求普办,要求每次用戶(hù)打開(kāi)app的時(shí)候工扎,請(qǐng)求后臺(tái)的接口,查看是否有最新版本的包衔蹲,如果有更新肢娘,則去后臺(tái)偷偷的下載最新版本的apk,考慮到用戶(hù)流量舆驶,要求下載apk必須是在wifi環(huán)境下下載橱健,基于此需求,主要有如下幾個(gè)方面的考慮:
一沙廉、app首頁(yè)請(qǐng)求接口拘荡,根據(jù)后臺(tái)返回的最新版本號(hào),以及數(shù)據(jù)庫(kù)存的版本號(hào)撬陵,判斷是否需要開(kāi)始下載珊皿,還是接著上次下載
二、下載管理器:如果需要下載巨税,則開(kāi)啟service蟋定,service中開(kāi)啟一個(gè)線(xiàn)程,讓線(xiàn)程去下載apk草添,注意:如果wifi斷了驶兜,一定要關(guān)閉線(xiàn)程,關(guān)閉service
三、對(duì)wifi寫(xiě)個(gè)廣播接收者抄淑,如果wifi斷了屠凶,這時(shí)候應(yīng)該停止下載,如果wifi又連上了肆资,則繼續(xù)上次的下載
四矗愧、數(shù)據(jù)庫(kù):如果此時(shí)wifi斷了,然后新版本又下載了一部分了迅耘,此時(shí)需要暫停下載贱枣,將已經(jīng)下載的部分,包括下載的進(jìn)度颤专,新版的版本號(hào)等信息存入數(shù)據(jù)庫(kù)中,基于此考慮钠乏,第一條栖秕,還需要根據(jù)數(shù)據(jù)庫(kù)存入的版本號(hào)做比對(duì),因?yàn)槿绻镜厥?晓避,數(shù)據(jù)庫(kù)存的是2簇捍,這時(shí)候請(qǐng)求接口,發(fā)現(xiàn)接口返回是3俏拱,則需要更新數(shù)據(jù)庫(kù)暑塑,并將已經(jīng)下載的本地文件刪除,重新下載
貼部分代碼:
一锅必、
//請(qǐng)求是否需要更新事格,請(qǐng)求后臺(tái)的接口
requestVersionUpdate();
//后臺(tái)接口返回
@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);//得到數(shù)據(jù)庫(kù)操作對(duì)象
threadInfo=mDao.select();//查詢(xún)數(shù)據(jù)庫(kù)里保存的紀(jì)錄,如果沒(méi)有搞隐,則為空
if(null!=threadInfo) {
dbVersion=threadInfo.getVersioncode();//得到數(shù)據(jù)庫(kù)里保存的,上次下載的apk的版本號(hào)
}
fileName="/ceshi.apk";
forceInstall= data.force_update;//是否強(qiáng)制用戶(hù)安裝
//當(dāng)前程序的版本號(hào)
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) {
//通知下載器去下載,并且把紀(jì)錄插入數(shù)據(jù)庫(kù)中
ThreadInfo info =newThreadInfo(0,download_link,0,0,0,newVersion, MySqliteHelper.UNDOWNLOAD,intro, DownloadService.DOWNLOAD_PATH,fileName);
if(!mDao.isExists(newVersion)) {
mDao.insertThread(info);
}
//如果文件已經(jīng)存在劣纲,則刪除文件逢捺,防止用戶(hù)已經(jīng)部分下載了,然后把程序卸載了癞季,后來(lái)又重新安裝劫瞳,此時(shí)需要將文件刪除
File file =newFile(info.getDownloadFile());
if(file.exists()) {
FileUtil.deleteFile(file);
}
downloadHelper.downloadApk(info);
}else if(newVersion>dbVersion) {
//從數(shù)據(jù)庫(kù)里查詢(xún)是否下載過(guò)apk,如果有則刪除下載的apk文件绷柒,并且將dbversion更新為最新的版本號(hào)
File file =newFile(threadInfo.getDownloadFile() +threadInfo.getFileName());
Log.i("anru","newVersion > dbVersion:::file:"+ file.toString());
// 路徑為文件且不為空則進(jìn)行刪除
if(file.isFile() && file.exists()) {
file.delete();
mDao.deleteThread(dbVersion);
}
//刪除之后志于,去啟動(dòng)下載
//通知下載器去下載
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) {
//從數(shù)據(jù)庫(kù)里查詢(xún)是否下載過(guò)apk,如果有則刪除下載的apk文件辉巡,并且將dbversion更新為最新的版本號(hào)
File file =newFile(threadInfo.getDownloadFile() +threadInfo.getFileName());
if(threadInfo.getApkstatus() != MySqliteHelper.DOWNLOAD_COM) {
//繼續(xù)去下載
downloadHelper.downloadApk(threadInfo);
}else if(!MD5Helper.getMD5(file).equals(data.apk_md5)) {//如果md5值不一致恨憎,則刪除原文件,重新下載
// 路徑為文件且不為空則進(jìn)行刪除
if(file.isFile() && file.exists()) {
file.delete();
mDao.deleteThread(dbVersion);
}
//刪除之后,去啟動(dòng)下載
//通知下載器去下載
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{
//提示用戶(hù)安裝
isShowInstall=1;
}
}
}
}
二憔恳、下載管理器:
//開(kāi)啟服務(wù)
Intent intent =newIntent(context, DownloadService.class);
intent.putExtra("info",info);
DownloadTask.mIsPause=false;
context.startService(intent);
//在服務(wù)頁(yè)面瓤荔,開(kāi)啟線(xiàn)程
@Override
public intonStartCommand(Intent intent,intflags,intstartId) {
try{
ThreadInfo info = (ThreadInfo) intent.getSerializableExtra("info");
if(info.getApkstatus() != MySqliteHelper.DOWNLOAD_COM) {//如果暫時(shí)未下載,去下載
//判斷網(wǎng)絡(luò)狀態(tài)
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);
}
//下載的線(xiàn)程
classDownLoadThread extends Thread {
privateThreadInfo info;
public DownLoadThread(ThreadInfo info) {
this.info= info;
}
@Override
public voidrun() {
Log.i("anru","download開(kāi)始下載");
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");
// 設(shè)置下載位置
int start =info.getStart() +info.getFinished();
conn.setRequestProperty("Range",
"bytes="+ start +"-"+info.getEnd());
// 設(shè)置文件寫(xiě)入位置
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();
// 開(kāi)始下載
if(conn.getResponseCode() ==206|| conn.getResponseCode() ==200) {//206 Partial Content
// 讀取數(shù)據(jù)
in = conn.getInputStream();
intlen = -1;
byte[] b =new byte[1024*4];
longtime = System.currentTimeMillis();
while((len = in.read(b)) != -1) {
// 寫(xiě)入文件
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);
// 在下載暫停時(shí),保存下載進(jìn)度
if(mIsPause) {
Log.i("anru","mIsPause");
return;
}
}
}
}catch(Exception e) {
Log.e("anru","跳出來(lái)了");
}finally{
try{
raf.close();
if(null!= in) {
in.close();
}
conn.disconnect();
}catch(Exception e) {
e.printStackTrace();
}
}
}
三钥组、wifi監(jiān)聽(tīng)器廣播
@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)) {
//繼續(xù)去下載
DownloadHelper downloadHelper =newDownloadHelper(context);
ThreadDaoImpl mDao =newThreadDaoImpl(context);
ThreadInfo threadInfo = mDao.select();
downloadHelper.downloadApk(threadInfo);
}
}
}
四输硝、數(shù)據(jù)庫(kù):
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);
上邊代碼只挑了一些比較重點(diǎn)的貼了,如果想下載demo程梦,鏈接:
http://download.csdn.net/detail/forever521_/9510974