android 从服务器下载更新新版本软件 demo

下面介绍的是apk如何进行版本的检测及下载更新!

最终效果:

更新前:


更新提示:




下载后提示安装:


安装更新后:


由于版本的更新及下载都是通过网络从服务端上获取的,所以需要一个服务端。

新建一个服务端 updateApkServer,在这里该服务端没有特殊用途,只用来提供版本信息而已。其项目结构图:


所有的版本信息记录在 version.xml

Java代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <update>
  3. <version>2.0_20120530</version>
  4. <versionCode>2</versionCode>
  5. <updateTime>2012-05-30</updateTime>
  6. <apkName>安卓_02_20120530.apk</apkName>
  7. <downloadURL>http://localhost:8080/updateApkServer/sems.apk</downloadURL>
  8. <displayMessage>新版本发布,赶紧下载吧##1.新增A功能##2.新增B功能##3.新增C功能</displayMessage>
  9. </update>

服务端上有个updateApkDemo2.apk,其实就是把下面的客户端改了下内容和名称把它扔了进来,只是为了个demo下载演示而已。

OK,服务端就这样了。

下面是android端。

客户端项目结构图:


UpdateApkDemoActivity.java

Java代码 收藏代码
  1. packagecom.royal.updateApk;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. /**
  5. *更新视图界面类
  6. *
  7. *@authorRoyal
  8. *
  9. */
  10. publicclassUpdateApkDemoActivityextendsActivity{
  11. /**Calledwhentheactivityisfirstcreated.*/
  12. @Override
  13. publicvoidonCreate(BundlesavedInstanceState){
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.main);
  16. //版本更新检查
  17. UpdateManagerum=newUpdateManager(UpdateApkDemoActivity.this);
  18. um.checkUpdate();
  19. }
  20. }

一个比较重要的版本更新核心服务类,靠他了。

UpdateManager.java

Java代码 收藏代码
  1. packagecom.royal.updateApk;
  2. importjava.io.File;
  3. importjava.io.FileOutputStream;
  4. importjava.io.IOException;
  5. importjava.io.InputStream;
  6. importjava.net.HttpURLConnection;
  7. importjava.net.MalformedURLException;
  8. importjava.net.URL;
  9. importandroid.app.AlertDialog.Builder;
  10. importandroid.content.Context;
  11. importandroid.content.DialogInterface;
  12. importandroid.content.DialogInterface.OnClickListener;
  13. importandroid.content.Intent;
  14. importandroid.content.pm.PackageInfo;
  15. importandroid.content.pm.PackageManager;
  16. importandroid.content.pm.PackageManager.NameNotFoundException;
  17. importandroid.net.Uri;
  18. importandroid.os.Environment;
  19. importandroid.os.Handler;
  20. importandroid.os.Message;
  21. importandroid.view.LayoutInflater;
  22. importandroid.view.View;
  23. importandroid.widget.ProgressBar;
  24. importcom.royal.model.VersionInfo;
  25. importcom.royal.util.XMLParserUtil;
  26. /**
  27. *APK更新管理类
  28. *
  29. *@authorRoyal
  30. *
  31. */
  32. publicclassUpdateManager{
  33. //上下文对象
  34. privateContextmContext;
  35. //更新版本信息对象
  36. privateVersionInfoinfo=null;
  37. //下载进度条
  38. privateProgressBarprogressBar;
  39. //是否终止下载
  40. privatebooleanisInterceptDownload=false;
  41. //进度条显示数值
  42. privateintprogress=0;
  43. /**
  44. *参数为Context(上下文activity)的构造函数
  45. *
  46. *@paramcontext
  47. */
  48. publicUpdateManager(Contextcontext){
  49. this.mContext=context;
  50. }
  51. publicvoidcheckUpdate(){
  52. //从服务端获取版本信息
  53. info=getVersionInfoFromServer();
  54. if(info!=null){
  55. try{
  56. //获取当前软件包信息
  57. PackageInfopi=mContext.getPackageManager().getPackageInfo(mContext.getPackageName(),PackageManager.GET_CONFIGURATIONS);
  58. //当前软件版本号
  59. intversionCode=pi.versionCode;
  60. if(versionCode<info.getVersionCode()){
  61. //如果当前版本号小于服务端版本号,则弹出提示更新对话框
  62. showUpdateDialog();
  63. }
  64. }catch(NameNotFoundExceptione){
  65. e.printStackTrace();
  66. }
  67. }
  68. }
  69. /**
  70. *从服务端获取版本信息
  71. *
  72. *@return
  73. */
  74. privateVersionInfogetVersionInfoFromServer(){
  75. VersionInfoinfo=null;
  76. URLurl=null;
  77. try{
  78. //10.0.2.2相当于localhost
  79. url=newURL("http://10.0.2.2:8080/updateApkServer/version.xml");
  80. }catch(MalformedURLExceptione){
  81. e.printStackTrace();
  82. }
  83. if(url!=null){
  84. try{
  85. //使用HttpURLConnection打开连接
  86. HttpURLConnectionurlConn=(HttpURLConnection)url.openConnection();
  87. //读取服务端version.xml的内容(流)
  88. info=XMLParserUtil.getUpdateInfo(urlConn.getInputStream());
  89. urlConn.disconnect();
  90. }catch(IOExceptione){
  91. e.printStackTrace();
  92. }
  93. }
  94. returninfo;
  95. }
  96. /**
  97. *提示更新对话框
  98. *
  99. *@paraminfo
  100. *版本信息对象
  101. */
  102. privatevoidshowUpdateDialog(){
  103. Builderbuilder=newBuilder(mContext);
  104. builder.setTitle("版本更新");
  105. builder.setMessage(info.getDisplayMessage());
  106. builder.setPositiveButton("下载",newOnClickListener(){
  107. @Override
  108. publicvoidonClick(DialogInterfacedialog,intwhich){
  109. dialog.dismiss();
  110. //弹出下载框
  111. showDownloadDialog();
  112. }
  113. });
  114. builder.setNegativeButton("以后再说",newOnClickListener(){
  115. @Override
  116. publicvoidonClick(DialogInterfacedialog,intwhich){
  117. dialog.dismiss();
  118. }
  119. });
  120. builder.create().show();
  121. }
  122. /**
  123. *弹出下载框
  124. */
  125. privatevoidshowDownloadDialog(){
  126. Builderbuilder=newBuilder(mContext);
  127. builder.setTitle("版本更新中...");
  128. finalLayoutInflaterinflater=LayoutInflater.from(mContext);
  129. Viewv=inflater.inflate(R.layout.update_progress,null);
  130. progressBar=(ProgressBar)v.findViewById(R.id.pb_update_progress);
  131. builder.setView(v);
  132. builder.setNegativeButton("取消",newOnClickListener(){
  133. publicvoidonClick(DialogInterfacedialog,intwhich){
  134. dialog.dismiss();
  135. //终止下载
  136. isInterceptDownload=true;
  137. }
  138. });
  139. builder.create().show();
  140. //下载apk
  141. downloadApk();
  142. }
  143. /**
  144. *下载apk
  145. */
  146. privatevoiddownloadApk(){
  147. //开启另一线程下载
  148. ThreaddownLoadThread=newThread(downApkRunnable);
  149. downLoadThread.start();
  150. }
  151. /**
  152. *从服务器下载新版apk的线程
  153. */
  154. privateRunnabledownApkRunnable=newRunnable(){
  155. @Override
  156. publicvoidrun(){
  157. if(!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){
  158. //如果没有SD卡
  159. Builderbuilder=newBuilder(mContext);
  160. builder.setTitle("提示");
  161. builder.setMessage("当前设备无SD卡,数据无法下载");
  162. builder.setPositiveButton("确定",newOnClickListener(){
  163. @Override
  164. publicvoidonClick(DialogInterfacedialog,intwhich){
  165. dialog.dismiss();
  166. }
  167. });
  168. builder.show();
  169. return;
  170. }else{
  171. try{
  172. //服务器上新版apk地址
  173. URLurl=newURL("http://10.0.2.2:8080/updateApkServer/updateApkDemo2.apk");
  174. HttpURLConnectionconn=(HttpURLConnection)url.openConnection();
  175. conn.connect();
  176. intlength=conn.getContentLength();
  177. InputStreamis=conn.getInputStream();
  178. Filefile=newFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/updateApkFile/");
  179. if(!file.exists()){
  180. //如果文件夹不存在,则创建
  181. file.mkdir();
  182. }
  183. //下载服务器中新版本软件(写文件)
  184. StringapkFile=Environment.getExternalStorageDirectory().getAbsolutePath()+"/updateApkFile/"+info.getApkName();
  185. FileApkFile=newFile(apkFile);
  186. FileOutputStreamfos=newFileOutputStream(ApkFile);
  187. intcount=0;
  188. bytebuf[]=newbyte[1024];
  189. do{
  190. intnumRead=is.read(buf);
  191. count+=numRead;
  192. //更新进度条
  193. progress=(int)(((float)count/length)*100);
  194. handler.sendEmptyMessage(1);
  195. if(numRead<=0){
  196. //下载完成通知安装
  197. handler.sendEmptyMessage(0);
  198. break;
  199. }
  200. fos.write(buf,0,numRead);
  201. //当点击取消时,则停止下载
  202. }while(!isInterceptDownload);
  203. }catch(MalformedURLExceptione){
  204. e.printStackTrace();
  205. }catch(IOExceptione){
  206. e.printStackTrace();
  207. }
  208. }
  209. }
  210. };
  211. /**
  212. *声明一个handler来跟进进度条
  213. */
  214. privateHandlerhandler=newHandler(){
  215. publicvoidhandleMessage(Messagemsg){
  216. switch(msg.what){
  217. case1:
  218. //更新进度情况
  219. progressBar.setProgress(progress);
  220. break;
  221. case0:
  222. progressBar.setVisibility(View.INVISIBLE);
  223. //安装apk文件
  224. installApk();
  225. break;
  226. default:
  227. break;
  228. }
  229. };
  230. };
  231. /**
  232. *安装apk
  233. */
  234. privatevoidinstallApk(){
  235. //获取当前sdcard存储路径
  236. Fileapkfile=newFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/updateApkFile/"+info.getApkName());
  237. if(!apkfile.exists()){
  238. return;
  239. }
  240. Intenti=newIntent(Intent.ACTION_VIEW);
  241. //安装,如果签名不一致,可能出现程序未安装提示
  242. i.setDataAndType(Uri.fromFile(newFile(apkfile.getAbsolutePath())),"application/vnd.android.package-archive");
  243. mContext.startActivity(i);
  244. }
  245. }

update_prgress.xml 用于显示下载时的进度条

Java代码 收藏代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content">
  5. <ProgressBar
  6. android:id="@+id/pb_update_progress"
  7. style="?android:attr/progressBarStyleHorizontal"
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"/>
  10. </LinearLayout>

另外附上2个类,pojo、util

VersionInfo.java

Java代码 收藏代码
  1. packagecom.royal.model;
  2. /**
  3. *软件版本信息对象
  4. *
  5. *@authorRoyal
  6. *
  7. */
  8. publicclassVersionInfo{
  9. //版本描述字符串
  10. privateStringversion;
  11. //版本更新时间
  12. privateStringupdateTime;
  13. //新版本更新下载地址
  14. privateStringdownloadURL;
  15. //更新描述信息
  16. privateStringdisplayMessage;
  17. //版本号
  18. privateintversionCode;
  19. //apk名称
  20. privateStringapkName;
  21. publicStringgetVersion(){
  22. returnversion;
  23. }
  24. publicvoidsetVersion(Stringversion){
  25. this.version=version;
  26. }
  27. publicStringgetUpdateTime(){
  28. returnupdateTime;
  29. }
  30. publicvoidsetUpdateTime(StringupdateTime){
  31. this.updateTime=updateTime;
  32. }
  33. publicStringgetDownloadURL(){
  34. returndownloadURL;
  35. }
  36. publicvoidsetDownloadURL(StringdownloadURL){
  37. this.downloadURL=downloadURL;
  38. }
  39. publicStringgetDisplayMessage(){
  40. returndisplayMessage;
  41. }
  42. publicvoidsetDisplayMessage(StringdisplayMessage){
  43. this.displayMessage=displayMessage;
  44. }
  45. publicintgetVersionCode(){
  46. returnversionCode;
  47. }
  48. publicvoidsetVersionCode(intversionCode){
  49. this.versionCode=versionCode;
  50. }
  51. publicStringgetApkName(){
  52. returnapkName;
  53. }
  54. publicvoidsetApkName(StringapkName){
  55. this.apkName=apkName;
  56. }
  57. }

XMLParserUtil.java 就是用来解析服务端 version.xml 用的

Java代码 收藏代码
  1. packagecom.royal.util;
  2. importjava.io.IOException;
  3. importjava.io.InputStream;
  4. importorg.xmlpull.v1.XmlPullParser;
  5. importorg.xmlpull.v1.XmlPullParserException;
  6. importorg.xmlpull.v1.XmlPullParserFactory;
  7. importcom.royal.model.VersionInfo;
  8. /**
  9. *XML文档解析工具类
  10. *
  11. *@authorRoyal
  12. *
  13. */
  14. publicclassXMLParserUtil{
  15. /**
  16. *获取版本更新信息
  17. *
  18. *@paramis
  19. *读取连接服务version.xml文档的输入流
  20. *@return
  21. */
  22. publicstaticVersionInfogetUpdateInfo(InputStreamis){
  23. VersionInfoinfo=newVersionInfo();
  24. try{
  25. XmlPullParserFactoryfactory=XmlPullParserFactory.newInstance();
  26. factory.setNamespaceAware(true);
  27. XmlPullParserparser=factory.newPullParser();
  28. parser.setInput(is,"UTF-8");
  29. inteventType=parser.getEventType();
  30. while(eventType!=XmlPullParser.END_DOCUMENT){
  31. switch(eventType){
  32. caseXmlPullParser.START_TAG:
  33. if("version".equals(parser.getName())){
  34. info.setVersion(parser.nextText());
  35. }elseif("updateTime".equals(parser.getName())){
  36. info.setUpdateTime(parser.nextText());
  37. }elseif("updateTime".equals(parser.getName())){
  38. info.setUpdateTime(parser.nextText());
  39. }elseif("downloadURL".equals(parser.getName())){
  40. info.setDownloadURL(parser.nextText());
  41. }elseif("displayMessage".equals(parser.getName())){
  42. info.setDisplayMessage(parseTxtFormat(parser.nextText(),"##"));
  43. }elseif("apkName".equals(parser.getName())){
  44. info.setApkName(parser.nextText());
  45. }elseif("versionCode".equals(parser.getName())){
  46. info.setVersionCode(Integer.parseInt(parser.nextText()));
  47. }
  48. break;
  49. caseXmlPullParser.END_TAG:
  50. break;
  51. }
  52. eventType=parser.next();
  53. }
  54. }catch(XmlPullParserExceptione){
  55. e.printStackTrace();
  56. }catch(IOExceptione){
  57. e.printStackTrace();
  58. }
  59. returninfo;
  60. }
  61. /**
  62. *根据指定字符格式化字符串(换行)
  63. *
  64. *@paramdata
  65. *需要格式化的字符串
  66. *@paramformatChar
  67. *指定格式化字符
  68. *@return
  69. */
  70. publicstaticStringparseTxtFormat(Stringdata,StringformatChar){
  71. StringBufferbackData=newStringBuffer();
  72. String[]txts=data.split(formatChar);
  73. for(inti=0;i<txts.length;i++){
  74. backData.append(txts[i]);
  75. backData.append("\n");
  76. }
  77. returnbackData.toString();
  78. }
  79. }

最后一个别忘了开启网络权限和SD卡读写权限。

AndroidManifest.xml

Java代码 收藏代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.royal.updateApk"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-sdkandroid:minSdkVersion="8"/>
  7. <application
  8. android:icon="@drawable/ic_launcher"
  9. android:label="@string/app_name">
  10. <activity
  11. android:name=".UpdateApkDemoActivity"
  12. android:label="@string/app_name">
  13. <intent-filter>
  14. <actionandroid:name="android.intent.action.MAIN"/>
  15. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  16. </intent-filter>
  17. </activity>
  18. </application>
  19. <!--开启网络权限-->
  20. <uses-permissionandroid:name="android.permission.INTERNET"/>
  21. <!--在SDCard中创建与删除文件权限-->
  22. <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  23. <!--往SDCard写入数据权限-->
  24. <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  25. </manifest>
转自:http://royal2xiaose.iteye.com/blog/1551892
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值