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对象,得到InputStream
reader = 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 = new
ExistVersionUpdataDialog(iwudif.getMsg().getDesc(), iwudif.getMsg()
.getUpdateType(), this,
"版本更新", "温馨提示:检测到本机已存在最新版本的安装包" + apkName + ",可选择立即安装或重新下载。", "立即安装", "重新下载", new
ExistVersionUpdataDialog
.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() {
//更新后自动打开apk
Intent 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() {
@Override
public void run() {
// 将下载进度对话框取消
pBar.cancel();
installApk();
}
});
}
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public 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() + ":", "更新", "取消", new
VersionUpdataDialog
.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,帐号1
private 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,
I8WanVersionUpdataDialogCallBack
mI8WanVersionUpdataDialogCallBack) {
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.i8ShowExistVersionUpdataDialogCallBack
i8ShowExistVersionUpdataDialogCallBack) {
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">
<TextView
android: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"/>
<ImageView
android: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"/>
<ScrollView
android: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"-->
<TextView
android: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>
<!-- <TextView
android: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"/>-->
<RelativeLayout
android: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">
<TextView
android: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"/>
<LinearLayout
android:id="@+id/ll_OptionUpdata"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android: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"/>
<TextView
android: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 +
'}';
}
}
}
到这里就结束啦
评论