Android实现版本更新功能
毫无疑问,版本更新是每个应用不可缺少的功能之一 , 为了方便之后的集成 , 现在记录一下 , 这个是比较久之前写的了,目前使用的是HttpURLConnection进行网络请求 , 后期会使用其它网络请求优化,这篇注重逻辑的实现。
现在版本更新有两种处理方式了:
1、跳转到App应用市场(例如:应用宝、豌豆荚等等),通过应用市场下载更新安装。
2、在App内进行Apk下载,下载完成后更新安装。
我们这边使用第二种方式,为了方便大家理解,画了一张流程图:

实现流程:
1、启动页后调用方法
private UpdateInfo iwudif;//版本更新bean类private String path = "";//请求路径// 检测版本是否一致,private void isNeedUpdate() {new Thread(new Runnable() {public void run() {//调用网络请求的方法,获取后台配置的请求数据,path为请求路径iwudif = getUpDateInfo(path);if (null == iwudif) {Log.d("text", "没有更新");runOnUiThread(new Runnable() {public void run() {//进入到登录界面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值是否正确存在进入已存在更新,不存在进入show的对话框if (null != md5ByFile && md5ByFile.equals(iwudif.getMsg().getMd5())) {//弹出提示框,已经存在,是重新下载还是直接安装。existApkInstall(iwudif);} else {//apk没下载,是否更新对话框showUpdateDialog(iwudif);}} catch (FileNotFoundException e) {e.printStackTrace();//进入到登录界面jumpToI8LoginActivity();}} else {//apk没下载,是否更新对话框showUpdateDialog(iwudif);}} else {//强制更新时进入是否更新对话框showUpdateDialog(iwudif);}} else {//无更新//版本号一致,进入到登录界面jumpToI8LoginActivity();}}});}}}).start();}
2、获取升级信息的方法
/*** 获取升级信息*/public UpdateInfo getUpDateInfo(String path) {StringBuffer sb = new StringBuffer();String line;BufferedReader reader = null;try {// 创建一个url对象URL url = new URL(path);// 通過url对象,创建一个HttpURLConnection对象(连接)HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setRequestMethod("GET");urlConnection.setConnectTimeout(2000);urlConnection.setReadTimeout(2000);if (urlConnection.getResponseCode() == 200) {// 通过HttpURLConnection对象,得到InputStreamreader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));while ((line = reader.readLine()) != null) {sb.append(line);}String info = sb.toString();Log.d("text", "版本升级信息:" + info);//--------// 对升级的信息进行封装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、弹出提示框方法,已经存在,是重新下载还是直接安装
//是否重新下载private void existApkInstall(final UpdateInfo iwudif) {ExistVersionUpdataDialog existVersionUpdataDialog = newExistVersionUpdataDialog(iwudif.getMsg().getDesc(), iwudif.getMsg().getUpdateType(), this,"版本更新", "温馨提示:检测到本机已存在最新版本的安装包" + apkName + ",可选择立即安装或重新下载。", "立即安装", "重新下载", newExistVersionUpdataDialog.ExistVersionUpdataDialogCallBack() {public void sureUpdata(boolean isUpdata) {installApk();}public void downloadAgain(boolean isUpdata) {downFile(iwudif.getMsg().getUrl());}public void close(boolean isUpdata) {jumpToI8LoginActivity();//进入到登录界面}});//按对话框外区域不消失existVersionUpdataDialog .setCanceledOnTouchOutside(false);//按返回键也不起作用existVersionUpdataDialog .setCancelable(false);existVersionUpdataDialog .show();}
4、安装apk的方法
//安装apk,也可以进行静默安装private void installApk() {//更新后自动打开apkIntent intent = new Intent(Intent.ACTION_VIEW);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//如果不加,最后安装完成,点打开,无法打开新版本应用。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());//如果不加,最后不会提示完成、打开。}
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("请稍候...");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); // 设置进度条的总长度FileOutputStream fileOutputStream = null;if (is != null) {// 对apk进行保存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); // 实时更新进度了}}if (fileOutputStream != null) {fileOutputStream.flush();fileOutputStream.close();}//ui线程,然后进入主线程runOnUiThread(new Runnable() {@Overridepublic void run() {// 将下载进度对话框取消pBar.cancel();installApk();}});}} catch (Exception e) {e.printStackTrace();runOnUiThread(new Runnable() {@Overridepublic void run() {pBar.cancel();Toast.makeText(getApplicationContext(), "下载失败", Toast.LENGTH_LONG).show();jumpToI8LoginActivity();//进入到登录界面}});}}}.start();}
6、弹出下载apk的对话框方法
/*** 显示升级信息的对话框*/private void showUpdateDialog(final UpdateInfo iwudif) {VersionUpdataDialog dialog = new VersionUpdataDialog(iwudif.getMsg().getDesc(), iwudif.getMsg().getUpdateType(), this,"版本升级", "请升级APP版本至" + iwudif.getMsg().getVersion() + ":", "更新", "取消", newVersionUpdataDialog.VersionUpdataDialogCallBack() {public void sureDelete(boolean isUpdata) {downFile(iwudif.getMsg().getUrl());// 点击确定将apk下载}public void close(boolean isUpdata) {//MobclickAgent.onKillProcess(TCSplashActivity.this);android.os.Process.killProcess(android.os.Process.myPid());jumpToI8LoginActivity();//进入到登录界面}public void cancle(boolean isUpdata) {//isHaveHotUpdata();//判断是否有热更新jumpToI8LoginActivity();//进入到登录界面}});//按对话框外区域不消失dialog.setCanceledOnTouchOutside(false);//按返回键也不起作用dialog.setCancelable(false);dialog.show();}
7、获取当前时间的方法
//获取当前时间public static String getTime() {SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");Date curDate = new Date(System.currentTimeMillis());//获取当前时间return formatter.format(curDate);}
8、自定义版本更新对话框
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;// 标识是帐号登录还是手机登录;手机0,帐号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时是选择更新,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内容了。//选择更新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选择更新");//---------------//强制更新} else {Log.d("text","AAAAAA强制更新");//---------------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、自定义本机上已存在apk的对话框
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、自定义对话框布局
<?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 +'}';}}}
到这里就结束啦
评论
