标签:
在这篇文章中(参见 android中如何下载文件并显示下载进度 )我们讲到了如何下载文件的问题,今天我介绍如何实现应用的自动更新,其中下载apk模块用到了前一篇文章中的知识。当然这只是一个实现的框架,你需要根据自己的需求是改变一些细节。
自动更新的原理
其实就是客户端将自己的版本号与服务端的版本号进行比对,版本号小于服务端则意味着有新版本,当然服务端的版本号是需要人工放上去的。
先看看效果:
为了代码的简洁,我这里用原生的alert对话框。
点击下载之后:
下载完成安装的界面我就不张贴了。
使用方法:
很简单,在需要检查更新的地方加入如下代码:
1
2
|
updateChecker.checkForUpdates(); |
其中http://jcodecraeer.com/update.php返回的是服务器段存放的版本信息。服务端的版本信息分为三部分:
1.版本号;
2.版本描述;
3.存放apk的url(告诉客户端,在哪里下载新版本的apk);
以http://jcodecraeer.com/update.php返回的结果为例,返回的字符串具体是这样的:
1
|
{ "url" : "http://www.jcodecraeer.com/***.apk" , "versionCode" : "2" , "updateMessage" : "1.修改了app图标
2.设备详情的显示方式" } |
这是一个json格式的字符串。
实现
有三个类:
其中
AppVersion是版本信息的模型类,基本上和服务端返回的东西是相对应的。
DownloadService是下载模块。
UpdateChecker是检查更新,调用下载模块,下载完安装的工具类。
AppVersion
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.jcodecraeer.jcode.update; public
class AppVersion { private
String updateMessage; private
String apkUrl; private
int apkCode; public
static final String APK_DOWNLOAD_URL = "url" ; public
static final String APK_UPDATE_CONTENT = "updateMessage" ; public
static final String APK_VERSION_CODE = "versionCode" ; public
void setUpdateMessage(String updateMessage) { this .updateMessage
= updateMessage; } public
String getUpdateMessage() { return
updateMessage; } public
void setApkUrl(String apkUrl) { this .apkUrl
= apkUrl; } public
String getApkUrl() { return
apkUrl; } public
void setApkCode(int apkCode) { this .apkCode
= apkCode; } public
int getApkCode() { return
apkCode; } } |
DownloadService
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
|
package
com.jcodecraeer.jcode.update; import
java.io.BufferedInputStream; import
java.io.FileOutputStream; import
java.io.IOException; import
java.io.InputStream; import
java.io.OutputStream; import
java.net.URL; import
java.net.URLConnection; import
java.util.ArrayList; import
java.util.Date; import
java.util.HashMap; import
java.util.Map; import
org.jsoup.Jsoup; import
org.jsoup.nodes.Document; import
org.jsoup.nodes.Element; import
org.jsoup.select.Elements; import
com.jcodecraeer.PullToRefreshListView; import
android.annotation.SuppressLint; import
android.app.AlertDialog; import
android.app.IntentService; import
android.content.ContentResolver; import
android.content.ContentUris; import
android.content.Context; import
android.content.DialogInterface; import
android.content.Intent; import
android.content.res.TypedArray; import
android.database.Cursor; import
android.graphics.Rect; import
android.graphics.drawable.ColorDrawable; import
android.net.Uri; import
android.os.Bundle; import
android.os.Handler; import
android.os.Message; import
android.os.ResultReceiver; import
android.provider.ContactsContract; import
android.provider.MediaStore.Images; import
android.provider.MediaStore.Images.ImageColumns; import
android.support.v4.app.Fragment; import
android.util.DisplayMetrics; import
android.util.Log; import
android.util.SparseBooleanArray; import
android.view.LayoutInflater; import
android.view.Menu; import
android.view.MenuInflater; import
android.view.MenuItem; import
android.view.View; import
android.view.ViewGroup; import
android.view.ViewGroup.LayoutParams; import
android.widget.AbsListView; import
android.widget.AdapterView; import
android.widget.AdapterView.OnItemClickListener; import
android.widget.GridView; import
android.widget.ShareActionProvider; import
android.widget.TextView; import
android.widget.Toast; import
android.view.ActionMode; public
class DownloadService extends IntentService { public
static final int UPDATE_PROGRESS = 8344; public
DownloadService() { super ( "DownloadService" ); } @Override protected
void onHandleIntent(Intent intent) { String
urlToDownload = intent.getStringExtra( "url" ); String
fileDestination = intent.getStringExtra( "dest" ); ResultReceiver
receiver = (ResultReceiver) intent.getParcelableExtra( "receiver" ); try
{ URL
url = new
URL(urlToDownload); URLConnection
connection = url.openConnection(); connection.connect(); //
this will be useful so that you can show a typical 0-100% progress bar int
fileLength = connection.getContentLength(); //
download the file InputStream
input = new
BufferedInputStream(connection.getInputStream()); OutputStream
output = new
FileOutputStream(fileDestination); byte
data[] = new
byte[100]; long
total = 0; int
count; while
((count = input.read(data)) != -1) { total
+= count; //
publishing the progress.... Bundle
resultData = new
Bundle(); resultData.putInt( "progress"
,(int) (total * 100 / fileLength)); receiver.send(UPDATE_PROGRESS,
resultData); output.write(data,
0, count); } output.flush(); output.close(); input.close(); }
catch
(IOException e) { e.printStackTrace(); } Bundle
resultData = new
Bundle(); resultData.putInt( "progress"
,100); receiver.send(UPDATE_PROGRESS,
resultData); } } |
UpdateChecker
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
package
com.jcodecraeer.jcode.update; import
java.io.BufferedReader; import
java.io.File; import
java.io.IOException; import
java.io.InputStream; import
java.io.InputStreamReader; import
java.net.HttpURLConnection; import
java.net.URL; import
java.util.ArrayList; import
java.util.Date; import
java.util.zip.GZIPInputStream; import
org.json.JSONException; import
org.json.JSONObject; import
com.jcodecraeer.jcode.Code; import
android.app.AlertDialog; import
android.app.ProgressDialog; import
android.content.Context; import
android.content.DialogInterface; import
android.content.Intent; import
android.content.pm.PackageManager; import
android.net.Uri; import
android.os.Bundle; import
android.os.Environment; import
android.os.Handler; import
android.os.Message; import
android.os.ResultReceiver; import
android.util.Log; import
android.widget.Toast; public
class UpdateChecker{ private
static final String TAG = "UpdateChecker" ; private
Context mContext; //检查版本信息的线程 private
Thread mThread; //版本对比地址 private
String mCheckUrl; private
AppVersion mAppVersion; //下载apk的对话框 private
ProgressDialog mProgressDialog; private
File apkFile; public
void setCheckUrl(String url) { mCheckUrl
= url; } public
UpdateChecker(Context context) { mContext
= context; //
instantiate it within the onCreate method mProgressDialog
= new
ProgressDialog(context); mProgressDialog.setMessage( "正在下载" ); mProgressDialog.setIndeterminate( false ); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setCancelable( true ); mProgressDialog.setOnCancelListener( new
DialogInterface.OnCancelListener() { @Override public
void onCancel(DialogInterface dialog) { } }); mProgressDialog.setOnDismissListener( new
DialogInterface.OnDismissListener() { @Override public
void onDismiss(DialogInterface dialog) { //
TODO Auto-generated method stub } }); } public
void checkForUpdates() { if (mCheckUrl
== null )
{ //throw
new Exception("checkUrl can not be null"); return ; } final
Handler handler = new
Handler(){ public
void handleMessage(Message msg) { if
(msg.what == 1) { mAppVersion
= (AppVersion) msg.obj; try { int
versionCode = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode; if
(mAppVersion.getApkCode() > versionCode) { showUpdateDialog(); }
else
{ //Toast.makeText(mContext,
"已经是最新版本", Toast.LENGTH_SHORT).show(); } } catch
(PackageManager.NameNotFoundException ignored) { // } } } }; mThread
= new
Thread() { @Override public
void run() { //if
(isNetworkAvailable(mContext)) { Message
msg = new
Message(); String
json = sendPost(); Log.i( "jianghejie" , "json
= " +json); if (json!= null ){ AppVersion
appVersion = parseJson(json); msg.what
= 1; msg.obj
= appVersion; handler.sendMessage(msg); } else { Log.e(TAG,
"can‘t
get app update json" ); } } }; mThread.start(); } protected
String sendPost() { HttpURLConnection
uRLConnection = null ; InputStream
is = null ; BufferedReader
buffer = null ; String
result = null ; try
{ URL
url = new
URL(mCheckUrl); uRLConnection
= (HttpURLConnection) url.openConnection(); uRLConnection.setDoInput( true ); uRLConnection.setDoOutput( true ); uRLConnection.setRequestMethod( "POST" ); uRLConnection.setUseCaches( false ); uRLConnection.setConnectTimeout(10
* 1000); uRLConnection.setReadTimeout(10
* 1000); uRLConnection.setInstanceFollowRedirects( false ); uRLConnection.setRequestProperty( "Connection" ,
"Keep-Alive" ); uRLConnection.setRequestProperty( "Charset" ,
"UTF-8" ); uRLConnection.setRequestProperty( "Accept-Encoding" ,
"gzip,
deflate" ); uRLConnection.setRequestProperty( "Content-Type" ,
"application/json" ); uRLConnection.connect(); is
= uRLConnection.getInputStream(); String
content_encode = uRLConnection.getContentEncoding(); if
( null
!= content_encode && ! "" .equals(content_encode)
&& content_encode.equals( "gzip" ))
{ is
= new
GZIPInputStream(is); } buffer
= new
BufferedReader( new
InputStreamReader(is)); StringBuilder
strBuilder = new
StringBuilder(); String
line; while
((line = buffer.readLine()) != null )
{ strBuilder.append(line); } result
= strBuilder.toString(); }
catch
(Exception e) { Log.e(TAG,
"http
post error" ,
e); }
finally { if (buffer!= null ){ try
{ buffer.close(); }
catch
(IOException e) { e.printStackTrace(); } } if (is!= null ){ try
{ is.close(); }
catch
(IOException e) { e.printStackTrace(); } } if (uRLConnection!= null ){ uRLConnection.disconnect(); } } return
result; } private
AppVersion parseJson(String json) { AppVersion
appVersion = new
AppVersion(); try
{ JSONObject
obj = new
JSONObject(json); String
updateMessage = obj.getString(AppVersion.APK_UPDATE_CONTENT); String
apkUrl = obj.getString(AppVersion.APK_DOWNLOAD_URL); int
apkCode = obj.getInt(AppVersion.APK_VERSION_CODE); appVersion.setApkCode(apkCode); appVersion.setApkUrl(apkUrl); appVersion.setUpdateMessage(updateMessage); }
catch
(JSONException e) { Log.e(TAG,
"parse
json error" ,
e); } return
appVersion; } public
void showUpdateDialog() { AlertDialog.Builder
builder = new
AlertDialog.Builder(mContext); //builder.setIcon(R.drawable.icon); builder.setTitle( "有新版本" ); builder.setMessage(mAppVersion.getUpdateMessage()); builder.setPositiveButton( "下载" , new
DialogInterface.OnClickListener() { public
void onClick(DialogInterface dialog, int whichButton) { downLoadApk(); } }); builder.setNegativeButton( "忽略" , new
DialogInterface.OnClickListener() { public
void onClick(DialogInterface dialog, int whichButton) { } }); builder.show();
} public
void downLoadApk() { String
apkUrl = mAppVersion.getApkUrl(); String
dir = mContext.getExternalFilesDir( "apk" ).getAbsolutePath(); File
folder = Environment.getExternalStoragePublicDirectory(dir); if (folder.exists()
&& folder.isDirectory()) { //do
nothing } else
{ folder.mkdirs(); } String
filename = apkUrl.substring(apkUrl.lastIndexOf( "/" ),apkUrl.length()); String
destinationFilePath = dir + "/"
+ filename; apkFile
= new
File(destinationFilePath); mProgressDialog.show(); Intent
intent = new
Intent(mContext, DownloadService.class); intent.putExtra( "url" ,
apkUrl); intent.putExtra( "dest" ,
destinationFilePath); intent.putExtra( "receiver" ,
new
DownloadReceiver( new
Handler())); mContext.startService(intent); } private
class DownloadReceiver extends ResultReceiver{ public
DownloadReceiver(Handler handler) { super (handler); } @Override protected
void onReceiveResult(int resultCode, Bundle resultData) { super .onReceiveResult(resultCode,
resultData); if
(resultCode == DownloadService.UPDATE_PROGRESS) { int
progress = resultData.getInt( "progress" ); mProgressDialog.setProgress(progress); if
(progress == 100) { mProgressDialog.dismiss(); //如果没有设置SDCard写权限,或者没有sdcard,apk文件保存在内存中,需要授予权限才能安装 String[]
command = { "chmod" , "777" ,apkFile.toString()}; try { ProcessBuilder
builder = new
ProcessBuilder(command); builder.start(); Intent
intent = new
Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive" ); mContext.startActivity(intent); } catch
(Exception e){ } } } } } } |
所有代码都已经贴出来了。
这个代码是完全可以用的,但是有些细节问题需要改进。
标签:
原文地址:http://blog.csdn.net/jian_csdn/article/details/43483795