Android實(shí)現(xiàn)版本更新功能
毫無(wú)疑問(wèn),版本更新是每個(gè)應(yīng)用不可缺少的功能之一 , 為了方便之后的集成 , 現(xiàn)在記錄一下 , 這個(gè)是比較久之前寫(xiě)的了,目前使用的是HttpURLConnection進(jìn)行網(wǎng)絡(luò)請(qǐng)求 , 后期會(huì)使用其它網(wǎng)絡(luò)請(qǐng)求優(yōu)化,這篇注重邏輯的實(shí)現(xiàn)。
現(xiàn)在版本更新有兩種處理方式了:
1、跳轉(zhuǎn)到App應(yīng)用市場(chǎng)(例如:應(yīng)用寶、豌豆莢等等),通過(guò)應(yīng)用市場(chǎng)下載更新安裝。
2、在App內(nèi)進(jìn)行Apk下載,下載完成后更新安裝。
我們這邊使用第二種方式,為了方便大家理解,畫(huà)了一張流程圖:

實(shí)現(xiàn)流程:
1、啟動(dòng)頁(yè)后調(diào)用方法
private UpdateInfo iwudif;//版本更新bean類private String path = "";//請(qǐng)求路徑// 檢測(cè)版本是否一致,private void isNeedUpdate() {new Thread(new Runnable() {public void run() {//調(diào)用網(wǎng)絡(luò)請(qǐng)求的方法,獲取后臺(tái)配置的請(qǐng)求數(shù)據(jù),path為請(qǐng)求路徑iwudif = getUpDateInfo(path);if (null == iwudif) {Log.d("text", "沒(méi)有更新");runOnUiThread(new Runnable() {public void run() {//進(jìn)入到登錄界面jumpToI8LoginActivity();}});} else {Log.d("text", "有更新");apkName = I8SP.getDownloadBag(TCSplashActivity.this);//保存apk的name到sp中runOnUiThread(new Runnable() {public void run() {//有更新if (iwudif.getMsg().getUrl() != null) {if (UPDATATYPE == iwudif.getMsg().getUpdateType()) {File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), apkName);//新版本存在,直接安裝if (file.exists()) {try {String md5ByFile = StatusBarUtil.getMd5ByFile(file);//判定md5值是否正確存在進(jìn)入已存在更新,不存在進(jìn)入show的對(duì)話框if (null != md5ByFile && md5ByFile.equals(iwudif.getMsg().getMd5())) {//彈出提示框,已經(jīng)存在,是重新下載還是直接安裝。existApkInstall(iwudif);} else {//apk沒(méi)下載,是否更新對(duì)話框showUpdateDialog(iwudif);}} catch (FileNotFoundException e) {e.printStackTrace();//進(jìn)入到登錄界面jumpToI8LoginActivity();}} else {//apk沒(méi)下載,是否更新對(duì)話框showUpdateDialog(iwudif);}} else {//強(qiáng)制更新時(shí)進(jìn)入是否更新對(duì)話框showUpdateDialog(iwudif);}} else {//無(wú)更新//版本號(hào)一致,進(jìn)入到登錄界面jumpToI8LoginActivity();}}});}}}).start();}
2、獲取升級(jí)信息的方法
/*** 獲取升級(jí)信息*/public UpdateInfo getUpDateInfo(String path) {StringBuffer sb = new StringBuffer();String line;BufferedReader reader = null;try {// 創(chuàng)建一個(gè)url對(duì)象URL url = new URL(path);// 通過(guò)url對(duì)象,創(chuàng)建一個(gè)HttpURLConnection對(duì)象(連接)HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setRequestMethod("GET");urlConnection.setConnectTimeout(2000);urlConnection.setReadTimeout(2000);if (urlConnection.getResponseCode() == 200) {// 通過(guò)HttpURLConnection對(duì)象,得到InputStreamreader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));while ((line = reader.readLine()) != null) {sb.append(line);}String info = sb.toString();Log.d("text", "版本升級(jí)信息:" + info);//--------// 對(duì)升級(jí)的信息進(jìn)行封裝Gson gson = new Gson();Type type = new TypeToken<UpdateInfo>() {}.getType();return gson.fromJson(info, type);}} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (reader != null) {reader.close();}} catch (Exception e) {e.printStackTrace();}}return null;}
3、彈出提示框方法,已經(jīng)存在,是重新下載還是直接安裝
//是否重新下載private void existApkInstall(final UpdateInfo iwudif) {ExistVersionUpdataDialog existVersionUpdataDialog = newExistVersionUpdataDialog(iwudif.getMsg().getDesc(), iwudif.getMsg().getUpdateType(), this,"版本更新", "溫馨提示:檢測(cè)到本機(jī)已存在最新版本的安裝包" + apkName + ",可選擇立即安裝或重新下載。", "立即安裝", "重新下載", newExistVersionUpdataDialog.ExistVersionUpdataDialogCallBack() {public void sureUpdata(boolean isUpdata) {installApk();}public void downloadAgain(boolean isUpdata) {downFile(iwudif.getMsg().getUrl());}public void close(boolean isUpdata) {jumpToI8LoginActivity();//進(jìn)入到登錄界面}});//按對(duì)話框外區(qū)域不消失existVersionUpdataDialog .setCanceledOnTouchOutside(false);//按返回鍵也不起作用existVersionUpdataDialog .setCancelable(false);existVersionUpdataDialog .show();}
4、安裝apk的方法
//安裝apk,也可以進(jìn)行靜默安裝private void installApk() {//更新后自動(dòng)打開(kāi)apkIntent intent = new Intent(Intent.ACTION_VIEW);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//如果不加,最后安裝完成,點(diǎn)打開(kāi),無(wú)法打開(kāi)新版本應(yīng)用。intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), apkName)), "application/vnd.android.package-archive");startActivityForResult(intent, 10);android.os.Process.killProcess(android.os.Process.myPid());//如果不加,最后不會(huì)提示完成、打開(kāi)。}
5、下載apk的方法
/*** 下載最新版本的apk** @param path apk下載地址private void downFile(final String path) {final ProgressDialog pBar = new ProgressDialog(TCSplashActivity.this);pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);pBar.setCancelable(false);pBar.setTitle("正在下載...");pBar.setMessage("請(qǐng)稍候...");pBar.setProgress(0);pBar.show();new Thread() {public void run() {try {URL url = new URL(path);HttpURLConnection con = (HttpURLConnection) url.openConnection();con.setReadTimeout(3000);con.setConnectTimeout(3000);con.setRequestProperty("Charset", "UTF-8");con.setRequestMethod("GET");if (con.getResponseCode() == 200) {int length = con.getContentLength();// 獲取文件大小InputStream is = con.getInputStream();pBar.setMax(100); // 設(shè)置進(jìn)度條的總長(zhǎng)度FileOutputStream fileOutputStream = null;if (is != null) {// 對(duì)apk進(jìn)行保存String[] split = getPackageName().split("\\.");int length1 = split.length - 1;apkName = "apkshow_" + split[length1] + "_" + getTime() + ".apk";I8SP.setDownloadBag(TCSplashActivity.this, apkName);File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),apkName);fileOutputStream = new FileOutputStream(file);byte[] buf = new byte[1024];int ch;int process = 0;while ((ch = is.read(buf)) != -1) {fileOutputStream.write(buf, 0, ch);process += ch;pBar.setProgress(process * 100 / length); // 實(shí)時(shí)更新進(jìn)度了}}if (fileOutputStream != null) {fileOutputStream.flush();fileOutputStream.close();}//ui線程,然后進(jìn)入主線程runOnUiThread(new Runnable() {@Overridepublic void run() {// 將下載進(jìn)度對(duì)話框取消pBar.cancel();installApk();}});}} catch (Exception e) {e.printStackTrace();runOnUiThread(new Runnable() {@Overridepublic void run() {pBar.cancel();Toast.makeText(getApplicationContext(), "下載失敗", Toast.LENGTH_LONG).show();jumpToI8LoginActivity();//進(jìn)入到登錄界面}});}}}.start();}
6、彈出下載apk的對(duì)話框方法
/*** 顯示升級(jí)信息的對(duì)話框*/private void showUpdateDialog(final UpdateInfo iwudif) {VersionUpdataDialog dialog = new VersionUpdataDialog(iwudif.getMsg().getDesc(), iwudif.getMsg().getUpdateType(), this,"版本升級(jí)", "請(qǐng)升級(jí)APP版本至" + iwudif.getMsg().getVersion() + ":", "更新", "取消", newVersionUpdataDialog.VersionUpdataDialogCallBack() {public void sureDelete(boolean isUpdata) {downFile(iwudif.getMsg().getUrl());// 點(diǎn)擊確定將apk下載}public void close(boolean isUpdata) {//MobclickAgent.onKillProcess(TCSplashActivity.this);android.os.Process.killProcess(android.os.Process.myPid());jumpToI8LoginActivity();//進(jìn)入到登錄界面}public void cancle(boolean isUpdata) {//isHaveHotUpdata();//判斷是否有熱更新jumpToI8LoginActivity();//進(jìn)入到登錄界面}});//按對(duì)話框外區(qū)域不消失dialog.setCanceledOnTouchOutside(false);//按返回鍵也不起作用dialog.setCancelable(false);dialog.show();}
7、獲取當(dāng)前時(shí)間的方法
//獲取當(dāng)前時(shí)間public static String getTime() {SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");Date curDate = new Date(System.currentTimeMillis());//獲取當(dāng)前時(shí)間return formatter.format(curDate);}
8、自定義版本更新對(duì)話框
public class I8ShowVersionUpdataDialog extends Dialog {public interface I8WanVersionUpdataDialogCallBack {void sureDelete(boolean isUpdata);void close(boolean isUpdata);void cancle(boolean isUpdata);}private String mUpdateContent;private int updateType;private Context mContext;private String mTitle;private String mTipContent;private I8ShowVersionUpdataDialog.I8WanVersionUpdataDialogCallBack mI8WanVersionUpdataDialogCallBack;// 標(biāo)識(shí)是帳號(hào)登錄還是手機(jī)登錄;手機(jī)0,帳號(hào)1private TextView tv_Title;private TextView tv_tip;private TextView tv_sure;private TextView tv_think;private ImageView tv_close;private String sureText;private String thinkText;private int contentViewWidth = -1;private TextView constraintUpdata;private LinearLayout OptionUpdata;private int UPDATATYPE = 0; //為0時(shí)是選擇更新,public I8ShowVersionUpdataDialog(String UpdataContent, int type, Context mContext, String mTitle,String mTipText,String sureText, String thinkText,I8WanVersionUpdataDialogCallBackmI8WanVersionUpdataDialogCallBack) {super(mContext);mUpdateContent = UpdataContent;updateType = type;this.mContext = mContext;this.mTitle = mTitle;this.mTipContent = mTipText;this.sureText = sureText;this.thinkText = thinkText;// this.contentViewWidth = width;this.mI8WanVersionUpdataDialogCallBack = mI8WanVersionUpdataDialogCallBack;}protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getContext().setTheme(CommonUtils.getIdByName("i8_dialog_login", "style", mContext.getPackageName(), mContext));View contentView = View.inflate(mContext,CommonUtils.getIdByName("i8wan_version_updata_dialog", "layout", mContext.getPackageName(), mContext),null);setContentView(contentView);if (contentViewWidth > 0)contentView.getLayoutParams().width = contentViewWidth;tv_Title = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_title", "id", mContext.getPackageName(), mContext));tv_tip = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_tipText", "id", mContext.getPackageName(), mContext));tv_sure = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_sureDelete", "id", mContext.getPackageName(), mContext));tv_think = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_think", "id", mContext.getPackageName(), mContext));constraintUpdata = (TextView) findViewById(CommonUtils.getIdByName("tv_constraintUpdata", "id", mContext.getPackageName(), mContext));OptionUpdata = (LinearLayout) findViewById(CommonUtils.getIdByName("ll_OptionUpdata", "id", mContext.getPackageName(), mContext));tv_close = (ImageView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_close", "id", mContext.getPackageName(), mContext));tv_Title.setText(mTitle);// tv_tip.setText(mTipContent + "\n" + "\n" + mUpdateContent);tv_tip.setText(mUpdateContent);//普通更新不要顯示第一行的mTipContent內(nèi)容了。//選擇更新Log.d("text","AAAAAAupdateType=="+updateType);//---------------if (UPDATATYPE == updateType) {tv_sure.setText(sureText);tv_think.setText(thinkText);tv_sure.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mI8WanVersionUpdataDialogCallBack.sureDelete(true);I8ShowVersionUpdataDialog.this.dismiss();}});tv_think.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mI8WanVersionUpdataDialogCallBack.cancle(true);I8ShowVersionUpdataDialog.this.dismiss();}});Log.d("text","AAAAAA選擇更新");//---------------//強(qiáng)制更新} else {Log.d("text","AAAAAA強(qiáng)制更新");//---------------tv_close.setVisibility(View.VISIBLE);tv_close.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mI8WanVersionUpdataDialogCallBack.close(true);I8ShowVersionUpdataDialog.this.dismiss();}});OptionUpdata.setVisibility(View.GONE);constraintUpdata.setVisibility(View.VISIBLE);constraintUpdata.setText(sureText);constraintUpdata.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mI8WanVersionUpdataDialogCallBack.sureDelete(true);I8ShowVersionUpdataDialog.this.dismiss();mI8WanVersionUpdataDialogCallBack.cancle(true);}});}}public boolean onKeyDown(int keyCode, KeyEvent event) {return true;}}
9、自定義本機(jī)上已存在apk的對(duì)話框
public class I8ShowExistVersionUpdataDialog extends Dialog{public interface i8ShowExistVersionUpdataDialogCallBack {void sureUpdata(boolean isUpdata);void downloadAgain(boolean isUpdata);void close(boolean isUpdata);}private String mUpdateContent;private int updateType;private Context mContext;private String mTitle;private String mTipContent;private I8ShowExistVersionUpdataDialog.i8ShowExistVersionUpdataDialogCallBack mi8ShowExistVersionUpdataDialogCallBack;private TextView tv_Title;private ImageView close;private TextView tv_tip;private TextView tv_sure;private TextView tv_think;private String sureText;private String thinkText;private TextView constraintUpdata;private LinearLayout OptionUpdata;public I8ShowExistVersionUpdataDialog(String UpdataContent, int type, Context mContext, String mTitle,String mTipText,String sureText, String thinkText,I8ShowExistVersionUpdataDialog.i8ShowExistVersionUpdataDialogCallBacki8ShowExistVersionUpdataDialogCallBack) {super(mContext);mUpdateContent = UpdataContent;updateType = type;this.mContext = mContext;this.mTitle = mTitle;this.mTipContent = mTipText;this.sureText = sureText;this.thinkText = thinkText;this.mi8ShowExistVersionUpdataDialogCallBack = i8ShowExistVersionUpdataDialogCallBack;}protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getContext().setTheme(CommonUtils.getIdByName("i8_dialog_login", "style", mContext.getPackageName(), mContext));View contentView = View.inflate(mContext,CommonUtils.getIdByName("i8wan_version_updata_dialog", "layout", mContext.getPackageName(), mContext),null);setContentView(contentView);tv_Title = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_title", "id", mContext.getPackageName(), mContext));close = (ImageView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_close", "id", mContext.getPackageName(), mContext));tv_tip = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_tipText", "id", mContext.getPackageName(), mContext));tv_sure = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_sureDelete", "id", mContext.getPackageName(), mContext));tv_think = (TextView) findViewById(CommonUtils.getIdByName("i8_comfirm_dialog_think", "id", mContext.getPackageName(), mContext));constraintUpdata = (TextView) findViewById(CommonUtils.getIdByName("tv_constraintUpdata", "id", mContext.getPackageName(), mContext));OptionUpdata = (LinearLayout) findViewById(CommonUtils.getIdByName("ll_OptionUpdata", "id", mContext.getPackageName(), mContext));close.setVisibility(View.VISIBLE);tv_Title.setText(mTitle);tv_tip.setText(mTipContent + "\n" + "\n" + mUpdateContent);tv_sure.setText(sureText);tv_think.setText(thinkText);tv_sure.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mi8ShowExistVersionUpdataDialogCallBack.sureUpdata(true);I8ShowExistVersionUpdataDialog.this.dismiss();}});tv_think.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mi8ShowExistVersionUpdataDialogCallBack.downloadAgain(true);I8ShowExistVersionUpdataDialog.this.dismiss();}});close.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {mi8ShowExistVersionUpdataDialogCallBack.close(true);I8ShowExistVersionUpdataDialog.this.dismiss();}});}public boolean onKeyDown(int keyCode, KeyEvent event) {return true;}}
10、自定義對(duì)話框布局
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/i8_popwin_bg"android:padding="@dimen/I8d6"><TextViewandroid:id="@+id/i8_comfirm_dialog_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_marginTop="@dimen/I8d5"android:text="Tiele"android:textColor="#353535"android:textSize="17sp"/><ImageViewandroid:id="@+id/i8_comfirm_dialog_close"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:src="@drawable/i8_popwin_close"android:visibility="gone"/><ScrollViewandroid:id="@+id/i8_comfirm_dialog_scroll"android:layout_width="match_parent"android:layout_height="191dp"android:layout_below="@+id/i8_comfirm_dialog_title"android:layout_marginBottom="@dimen/I8d8"android:layout_marginLeft="@dimen/I8d12"android:layout_marginRight="@dimen/I8d12"android:layout_marginTop="@dimen/I8d15"android:background="@drawable/i8wan_updata_scroll"android:fillViewport="true"android:scrollbarSize="4sp"android:scrollbarThumbVertical="@color/scrollball"android:scrollbars="vertical"><!--android:scrollbarStyle="outsideOverlay"android:scrollbarSize="3sp"android:fadeScrollbars="false"android:scrollbarThumbVertical="@color/scrollball"android:background="@drawable/i8_find_password_success_message_bg"--><TextViewandroid:id="@+id/i8_comfirm_dialog_tipText"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_vertical"android:paddingLeft="14dp"android:paddingRight="12dp"android:textColor="#353535"android:lineSpacingExtra="8dp"android:textSize="15sp"/></ScrollView><!-- <TextViewandroid:id="@+id/i8_comfirm_dialog_tipText"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/i8_comfirm_dialog_title"android:layout_marginBottom="@dimen/I8d8"android:layout_marginLeft="@dimen/I8d12"android:layout_marginRight="@dimen/I8d12"android:layout_marginTop="@dimen/I8d15"android:background="@drawable/i8_find_password_success_message_bg"android:gravity="center_vertical"android:textColor="#353535"android:textSize="15sp"/>--><RelativeLayoutandroid:id="@+id/rl_constraintUpdata"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/i8_comfirm_dialog_scroll"android:padding="@dimen/I8d6"><TextViewandroid:id="@+id/tv_constraintUpdata"android:layout_width="match_parent"android:layout_height="48dp"android:layout_marginRight="@dimen/I8d6"android:background="@drawable/i8_login_bg_blue"android:gravity="center"android:text="更新"android:textColor="@android:color/white"android:textSize="17sp"android:visibility="gone"/><LinearLayoutandroid:id="@+id/ll_OptionUpdata"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/i8_comfirm_dialog_sureDelete"android:layout_width="@dimen/I8d0"android:layout_height="48dp"android:layout_marginRight="@dimen/I8d6"android:layout_weight="1"android:background="@drawable/i8_login_bg_blue"android:gravity="center"android:text="@string/i8_comfirm_delete"android:textColor="@android:color/white"android:textSize="17sp"/><TextViewandroid:id="@+id/i8_comfirm_dialog_think"android:layout_width="@dimen/I8d0"android:layout_height="48dp"android:layout_marginLeft="@dimen/I8d6"android:layout_weight="1"android:background="@drawable/i8_popwin_comfirm_think_bg"android:gravity="center"android:text="@string/i8_comfirm_think"android:textColor="@android:color/white"android:textSize="17sp"/></LinearLayout></RelativeLayout>
11、版本更新的bean類
public class UpdateInfo {private int status;private UpdateInfoMessage msg;public int getStatus() {return status;}public UpdateInfoMessage getMsg() {return msg;}public void setStatus(int status) {this.status = status;}public void setMsg(UpdateInfoMessage msg) {this.msg = msg;}public class UpdateInfoMessage {private int id;private double version;private String desc;private int channel;private String url;private int updateType;private String md5;private int markCount;private int open;private int space;public int getOpen() {return open;}public int getSpace() {return space;}public void setOpen(int open) {this.open = open;}public void setSpace(int space) {this.space = space;}public void setId(int id) {this.id = id;}public void setVersion(double version) {this.version = version;}public void setDesc(String desc) {this.desc = desc;}public void setChannel(int channel) {this.channel = channel;}public void setUrl(String url) {this.url = url;}public void setUpdateType(int updateType) {this.updateType = updateType;}public void setMd5(String md5) {this.md5 = md5;}public void setMarkCount(int markCount) {this.markCount = markCount;}public int getId() {return id;}public double getVersion() {return version;}public String getDesc() {return desc;}public int getChannel() {return channel;}public String getUrl() {return url;}public int getUpdateType() {return updateType;}public String getMd5() {return md5;}public int getMarkCount() {return markCount;}public String toString() {return "I8WanUpdateInfoMessage{" +"id=" + id +", version=" + version +", desc='" + desc + '\'' +", channel=" + channel +", url='" + url + '\'' +", updateType=" + updateType +", md5='" + md5 + '\'' +", markCount=" + markCount +'}';}}}
到這里就結(jié)束啦
評(píng)論
圖片
表情
