文章目录
  1. 1. 简单介绍
  2. 2. 实例

简单介绍

在现在的大部分Android应用中,检测更新是一个很重要的功能。当有新的版本时推送给用户或让用户自己手动检测更新,或者放到Android应用市场上让提示更新。本篇介绍怎么实现手动检测更新。关于推送更新在以后篇章中介绍推送时可以用推送功能提醒更新。

实例

本章介绍的检测更新是通过对比客户端和服务器之间的版本号来实现。具体方式有很多种,这里就介绍比较常见的将版本信息写在一个XML文档上,客户端通过读取XML文档上的信息来对比,如果XML文档上有比客户端高的版本,则客户端通过XML文档提供的下载链接下载安装最新的APK。
新建一个Android项目CheckUpdate
UpdateInfoParser解析版本信息的XML文档工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.carlos.checkupdate;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;
import android.util.Xml;

/**
* 解析版本信息
* @author xiaobudian
*
*/
public class UpdateInfoParser {

private final static String TAG="Version";

public static List<UpdateInfo> getUpdateInfo(InputStream inputStream){

List<UpdateInfo> infos=null;
UpdateInfo info=null;

XmlPullParser parser=Xml.newPullParser();
try {
parser.setInput(inputStream, "utf-8");
int type=parser.getEventType();
Log.i(TAG, "服务器版本信息");
while(type!=XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_DOCUMENT:
infos=new ArrayList<UpdateInfo>();
break;
case XmlPullParser.START_TAG:
if (parser.getName().equals("information")) {
info=new UpdateInfo();
}else if ("versionCode".equals(parser.getName())) {
info.setVersionCode(Integer.valueOf(parser.nextText()));
Log.i(TAG, info.getVersionCode()+"");
}else if ("versionName".equals(parser.getName())) {
info.setVersionName(parser.nextText());
Log.i(TAG, info.getVersionName());
}else if ("apkUrl".equals(parser.getName())) {
info.setApkUrl(parser.nextText());
Log.i(TAG, info.getApkUrl());
}else if ("description".equals(parser.getName())) {
info.setDescription(parser.nextText());
Log.i(TAG, info.getDescription());
}
break;
case XmlPullParser.END_TAG:
if (parser.getName().equals("information")) {
infos.add(info);
}
break;
default:
break;
}
type=parser.next();
}

} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return infos;
}

}

UpdateInfo类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.carlos.checkupdate;

public class UpdateInfo {

private int versionCode;
private String versionName;
private String apkUrl;
private String description;
public int getVersionCode() {
return versionCode;
}
public void setVersionCode(int versionCode) {
this.versionCode = versionCode;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public String getApkUrl() {
return apkUrl;
}
public void setApkUrl(String apkUrl) {
this.apkUrl = apkUrl;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

MainActivity主类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package com.carlos.checkupdate;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

private TextView tv_current_version;
private TextView tv_check_version;
private Button b_check_update;

private int versionCode;
private String versionName;
private List<UpdateInfo> infos;
private int temp=0;
private int position = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

tv_current_version=getViewById(R.id.tv_current_version);
tv_check_version=getViewById(R.id.tv_check_version);
b_check_update=getViewById(R.id.b_check_update);

getCurrentVersion();
b_check_update.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
new Thread(runnable).start();
}
});

}

/**
* 获取当前版本
*/
private void getCurrentVersion(){
PackageManager manager=getPackageManager();
try {
PackageInfo info=manager.getPackageInfo(getPackageName(), 0);
versionCode=info.versionCode;
versionName=info.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
tv_current_version.setText("当前版本是:"+versionName);
}

Runnable runnable=new Runnable() {

@Override
public void run() {
get();
}
};

/**
* 检测是否有新版本
*/
void get() {
String path="http://xbdcc.github.io/tools/checkUpdate.xml";

try {
URL url = new URL(path);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10*000);//设置超时时间为10秒

InputStream inputStream=connection.getInputStream();
infos=UpdateInfoParser.getUpdateInfo(inputStream);
for(int i=0;i<infos.size();i++){
int j=infos.get(i).getVersionCode();
if (j>temp) {
temp=j;
position=i;
}
}
if (temp>versionCode) {
Log.i("Version", "有新的版本"+infos.get(position).getVersionName());
handler.sendEmptyMessage(1);
}else {
Log.i("Version", "当前已是最新版本");
handler.sendEmptyMessage(0);
}

} catch (MalformedURLException e) {
handler.sendEmptyMessage(4);
e.printStackTrace();
} catch (IOException e) {
handler.sendEmptyMessage(5);
e.printStackTrace();
}
};

Handler handler=new Handler(){
@SuppressLint("ShowToast") public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
tv_check_version.setText("当前已是最新版本");
break;
case 1:
tv_check_version.setText("服务器有新版本:"+infos.get(position).getVersionName());
showDialog();
break;
case 2:
tv_check_version.setText("下载..."+msg.arg1+"%");
break;
case 3:
Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
InstallApk();
break;
case 4:
Toast.makeText(MainActivity.this, "网址有误", Toast.LENGTH_SHORT).show();
break;
case 5:
Toast.makeText(MainActivity.this, "IO Exception", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
};
};

/**
* 是否下载安装对话框
*/
private void showDialog(){
AlertDialog.Builder builder=new Builder(this);
builder.setTitle("提示");
builder.setMessage("检测到新版本,是否更新\n"+"更新内容为:"+infos.get(position).getDescription());
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
Download();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}

/**
* 下载APK
*/
private void Download(){
new DownloadAsyncTask(MainActivity.this, handler).execute(infos.get(position).getApkUrl());
Toast.makeText(MainActivity.this, infos.get(position).getApkUrl(), Toast.LENGTH_SHORT).show();
}

/**
* 安装APK
*/
private void InstallApk(){
File file=new File(Environment.getExternalStorageDirectory(),"xiaobudian.apk");
Intent intent=new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}


@SuppressWarnings("unchecked")
<T extends View> T getViewById(int id){
return (T) findViewById(id);
}
}

异步任务下载APK工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.carlos.checkupdate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class DownloadAsyncTask extends AsyncTask<String, Integer, Void>{

private Context context;
private Handler handler;
private ProgressDialog dialog;

public DownloadAsyncTask(Context context, Handler handler) {
super();
this.context = context;
this.handler = handler;
}

/**
* 显示下载进度条
*/
@Override
protected void onPreExecute() {
dialog=new ProgressDialog(context);
dialog.setMax(100);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setTitle("下载进度");
dialog.show();
}

/**
* 后台下载APK
*/
@Override
protected Void doInBackground(String... arg0) {
try {
URL url=new URL(arg0[0]);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10*000);
connection.connect();
InputStream inputStream=connection.getInputStream();
int length=connection.getContentLength();
File file=new File(Environment.getExternalStorageDirectory(),"xiaobudian.apk");

//如果文件存在就删除重新下载
if (file.exists()) {
Log.i("Download", "删除文件成功");
file.delete();
}
FileOutputStream outputStream=new FileOutputStream(file);

int count=0;
int numread=0;
byte[] buffer=new byte[1024];

int progress=0;
int lastprogress=0;
while(true){
numread=inputStream.read(buffer);
count+=numread;
progress=(int)(((float)count/length)*100);
Log.i("Download---", "progress=="+progress+" lastprogress=="+lastprogress);
if (progress>=lastprogress+1) {
lastprogress=progress;
publishProgress(progress);
Message message=new Message();
message.what=2;
message.arg1=progress;
handler.sendMessage(message);
}
if (numread<=0) {
handler.sendEmptyMessage(3);
break;
}
outputStream.write(buffer, 0, numread);
}
connection.disconnect();
outputStream.close();
inputStream.close();

} catch (MalformedURLException e) {
handler.sendEmptyMessage(4);
e.printStackTrace();
} catch (IOException e) {
handler.sendEmptyMessage(5);
e.printStackTrace();
}

return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
dialog.setProgress(values[0]);
}

@Override
protected void onPostExecute(Void result) {
dialog.dismiss();
}
}

XML文档信息

手机先安装1.0的版本然后使用检测更新下载1.1版本的安装包,点击检测更新按钮检测更新

下载

下载完后自动安装

文章目录
  1. 1. 简单介绍
  2. 2. 实例