由于Android项目开源所致,市面上出现了N多安卓软件市场。为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量。因此我们有必要给我们的Android应用增加自动更新的功能。

既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息:

  1. <update>
  2. <version>2</version>
  3. <name>baidu_xinwen_1.1.0</name>
  4. <url>http://gdown.baidu.com/data/wisegame/f98d235e39e29031/baiduxinwen.apk</url>
  5. </update>

在这里我使用的是XML文件,方便读取。由于XML文件内容比较少,因此可通过DOM方式进行文件的解析:

  1. public class ParseXmlService
  2. {
  3. public HashMap<String, String> parseXml(InputStream inStream) throws Exception
  4. {
  5. HashMap<String, String> hashMap = new HashMap<String, String>();
  6. // 实例化一个文档构建器工厂
  7. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  8. // 通过文档构建器工厂获取一个文档构建器
  9. DocumentBuilder builder = factory.newDocumentBuilder();
  10. // 通过文档通过文档构建器构建一个文档实例
  11. Document document = builder.parse(inStream);
  12. //获取XML文件根节点
  13. Element root = document.getDocumentElement();
  14. //获得所有子节点
  15. NodeList childNodes = root.getChildNodes();
  16. for (int j = 0; j < childNodes.getLength(); j++)
  17. {
  18. //遍历子节点
  19. Node childNode = (Node) childNodes.item(j);
  20. if (childNode.getNodeType() == Node.ELEMENT_NODE)
  21. {
  22. Element childElement = (Element) childNode;
  23. //版本号
  24. if ("version".equals(childElement.getNodeName()))
  25. {
  26. hashMap.put("version",childElement.getFirstChild().getNodeValue());
  27. }
  28. //软件名称
  29. else if (("name".equals(childElement.getNodeName())))
  30. {
  31. hashMap.put("name",childElement.getFirstChild().getNodeValue());
  32. }
  33. //下载地址
  34. else if (("url".equals(childElement.getNodeName())))
  35. {
  36. hashMap.put("url",childElement.getFirstChild().getNodeValue());
  37. }
  38. }
  39. }
  40. return hashMap;
  41. }
  42. }

通过parseXml()方法,我们可以获取服务器上应用的版本、文件名以及下载地址。紧接着我们就需要获取到我们手机上应用的版本信息:

  1. /**
  2. * 获取软件版本号
  3. *
  4. * @param context
  5. * @return
  6. */
  7. private int getVersionCode(Context context)
  8. {
  9. int versionCode = 0;
  10. try
  11. {
  12. // 获取软件版本号,
  13. versionCode = context.getPackageManager().getPackageInfo("com.szy.update", 0).versionCode;
  14. } catch (NameNotFoundException e)
  15. {
  16. e.printStackTrace();
  17. }
  18. return versionCode;
  19. }

通过该方法我们获取到的versionCode对应AndroidManifest.xml下android:versionCode。android:versionCode和android:versionName两个属性分别表示版本号,版本名称。versionCode是整数型,而versionName是字符串。由于versionName是给用户看的,不太容易比较大小,升级检查时,就可以检查versionCode。把获取到的手机上应用版本与服务器端的版本进行比较,应用就可以判断处是否需要更新软件。

处理流程

 
处理代码

  1. package com.szy.update;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.net.HttpURLConnection;
  7. import java.net.MalformedURLException;
  8. import java.net.URL;
  9. import java.util.HashMap;
  10. import android.app.AlertDialog;
  11. import android.app.Dialog;
  12. import android.app.AlertDialog.Builder;
  13. import android.content.Context;
  14. import android.content.DialogInterface;
  15. import android.content.Intent;
  16. import android.content.DialogInterface.OnClickListener;
  17. import android.content.pm.PackageManager.NameNotFoundException;
  18. import android.net.Uri;
  19. import android.os.Environment;
  20. import android.os.Handler;
  21. import android.os.Message;
  22. import android.view.LayoutInflater;
  23. import android.view.View;
  24. import android.widget.ProgressBar;
  25. import android.widget.Toast;
  26. /**
  27. *@author coolszy
  28. *@date 2012-4-26
  29. *@blog http://blog.92coding.com
  30. */
  31. public class UpdateManager
  32. {
  33. /* 下载中 */
  34. private static final int DOWNLOAD = 1;
  35. /* 下载结束 */
  36. private static final int DOWNLOAD_FINISH = 2;
  37. /* 保存解析的XML信息 */
  38. HashMap<String, String> mHashMap;
  39. /* 下载保存路径 */
  40. private String mSavePath;
  41. /* 记录进度条数量 */
  42. private int progress;
  43. /* 是否取消更新 */
  44. private boolean cancelUpdate = false;
  45. private Context mContext;
  46. /* 更新进度条 */
  47. private ProgressBar mProgress;
  48. private Dialog mDownloadDialog;
  49. private Handler mHandler = new Handler()
  50. {
  51. public void handleMessage(Message msg)
  52. {
  53. switch (msg.what)
  54. {
  55. // 正在下载
  56. case DOWNLOAD:
  57. // 设置进度条位置
  58. mProgress.setProgress(progress);
  59. break;
  60. case DOWNLOAD_FINISH:
  61. // 安装文件
  62. installApk();
  63. break;
  64. default:
  65. break;
  66. }
  67. };
  68. };
  69. public UpdateManager(Context context)
  70. {
  71. this.mContext = context;
  72. }
  73. /**
  74. * 检测软件更新
  75. */
  76. public void checkUpdate()
  77. {
  78. if (isUpdate())
  79. {
  80. // 显示提示对话框
  81. showNoticeDialog();
  82. } else
  83. {
  84. Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();
  85. }
  86. }
  87. /**
  88. * 检查软件是否有更新版本
  89. *
  90. * @return
  91. */
  92. private boolean isUpdate()
  93. {
  94. // 获取当前软件版本
  95. int versionCode = getVersionCode(mContext);
  96. // 把version.xml放到网络上,然后获取文件信息
  97. InputStream inStream = ParseXmlService.class.getClassLoader().getResourceAsStream("version.xml");
  98. // 解析XML文件。 由于XML文件比较小,因此使用DOM方式进行解析
  99. ParseXmlService service = new ParseXmlService();
  100. try
  101. {
  102. mHashMap = service.parseXml(inStream);
  103. } catch (Exception e)
  104. {
  105. e.printStackTrace();
  106. }
  107. if (null != mHashMap)
  108. {
  109. int serviceCode = Integer.valueOf(mHashMap.get("version"));
  110. // 版本判断
  111. if (serviceCode > versionCode)
  112. {
  113. return true;
  114. }
  115. }
  116. return false;
  117. }
  118. /**
  119. * 获取软件版本号
  120. *
  121. * @param context
  122. * @return
  123. */
  124. private int getVersionCode(Context context)
  125. {
  126. int versionCode = 0;
  127. try
  128. {
  129. // 获取软件版本号,对应AndroidManifest.xml下android:versionCode
  130. versionCode = context.getPackageManager().getPackageInfo("com.szy.update", 0).versionCode;
  131. } catch (NameNotFoundException e)
  132. {
  133. e.printStackTrace();
  134. }
  135. return versionCode;
  136. }
  137. /**
  138. * 显示软件更新对话框
  139. */
  140. private void showNoticeDialog()
  141. {
  142. // 构造对话框
  143. AlertDialog.Builder builder = new Builder(mContext);
  144. builder.setTitle(R.string.soft_update_title);
  145. builder.setMessage(R.string.soft_update_info);
  146. // 更新
  147. builder.setPositiveButton(R.string.soft_update_updatebtn, new OnClickListener()
  148. {
  149. @Override
  150. public void onClick(DialogInterface dialog, int which)
  151. {
  152. dialog.dismiss();
  153. // 显示下载对话框
  154. showDownloadDialog();
  155. }
  156. });
  157. // 稍后更新
  158. builder.setNegativeButton(R.string.soft_update_later, new OnClickListener()
  159. {
  160. @Override
  161. public void onClick(DialogInterface dialog, int which)
  162. {
  163. dialog.dismiss();
  164. }
  165. });
  166. Dialog noticeDialog = builder.create();
  167. noticeDialog.show();
  168. }
  169. /**
  170. * 显示软件下载对话框
  171. */
  172. private void showDownloadDialog()
  173. {
  174. // 构造软件下载对话框
  175. AlertDialog.Builder builder = new Builder(mContext);
  176. builder.setTitle(R.string.soft_updating);
  177. // 给下载对话框增加进度条
  178. final LayoutInflater inflater = LayoutInflater.from(mContext);
  179. View v = inflater.inflate(R.layout.softupdate_progress, null);
  180. mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
  181. builder.setView(v);
  182. // 取消更新
  183. builder.setNegativeButton(R.string.soft_update_cancel, new OnClickListener()
  184. {
  185. @Override
  186. public void onClick(DialogInterface dialog, int which)
  187. {
  188. dialog.dismiss();
  189. // 设置取消状态
  190. cancelUpdate = true;
  191. }
  192. });
  193. mDownloadDialog = builder.create();
  194. mDownloadDialog.show();
  195. // 现在文件
  196. downloadApk();
  197. }
  198. /**
  199. * 下载apk文件
  200. */
  201. private void downloadApk()
  202. {
  203. // 启动新线程下载软件
  204. new downloadApkThread().start();
  205. }
  206. /**
  207. * 下载文件线程
  208. *
  209. * @author coolszy
  210. *@date 2012-4-26
  211. *@blog http://blog.92coding.com
  212. */
  213. private class downloadApkThread extends Thread
  214. {
  215. @Override
  216. public void run()
  217. {
  218. try
  219. {
  220. // 判断SD卡是否存在,并且是否具有读写权限
  221. if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
  222. {
  223. // 获得存储卡的路径
  224. String sdpath = Environment.getExternalStorageDirectory() + "/";
  225. mSavePath = sdpath + "download";
  226. URL url = new URL(mHashMap.get("url"));
  227. // 创建连接
  228. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  229. conn.connect();
  230. // 获取文件大小
  231. int length = conn.getContentLength();
  232. // 创建输入流
  233. InputStream is = conn.getInputStream();
  234. File file = new File(mSavePath);
  235. // 判断文件目录是否存在
  236. if (!file.exists())
  237. {
  238. file.mkdir();
  239. }
  240. File apkFile = new File(mSavePath, mHashMap.get("name"));
  241. FileOutputStream fos = new FileOutputStream(apkFile);
  242. int count = 0;
  243. // 缓存
  244. byte buf[] = new byte[1024];
  245. // 写入到文件中
  246. do
  247. {
  248. int numread = is.read(buf);
  249. count += numread;
  250. // 计算进度条位置
  251. progress = (int) (((float) count / length) * 100);
  252. // 更新进度
  253. mHandler.sendEmptyMessage(DOWNLOAD);
  254. if (numread <= 0)
  255. {
  256. // 下载完成
  257. mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
  258. break;
  259. }
  260. // 写入文件
  261. fos.write(buf, 0, numread);
  262. } while (!cancelUpdate);// 点击取消就停止下载.
  263. fos.close();
  264. is.close();
  265. }
  266. } catch (MalformedURLException e)
  267. {
  268. e.printStackTrace();
  269. } catch (IOException e)
  270. {
  271. e.printStackTrace();
  272. }
  273. // 取消下载对话框显示
  274. mDownloadDialog.dismiss();
  275. }
  276. };
  277. /**
  278. * 安装APK文件
  279. */
  280. private void installApk()
  281. {
  282. File apkfile = new File(mSavePath, mHashMap.get("name"));
  283. if (!apkfile.exists())
  284. {
  285. return;
  286. }
  287. // 通过Intent安装APK文件
  288. Intent i = new Intent(Intent.ACTION_VIEW);
  289. i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
  290. mContext.startActivity(i);
  291. }
  292. }

效果图

检查模拟器SDCARD是否存在下载文件:

Android应用自动更新功能的代码实现(转)的更多相关文章

  1. Android应用自动更新功能的代码实现

    由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必 ...

  2. Android 应用自动更新功能的代码

    由于Android项目开源所致,市面上出现了N多安卓软件市场.为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量.因此我们有必 ...

  3. [转]Android应用自动更新功能的代码实现

    本文转自:http://www.cnblogs.com/coolszy/archive/2012/04/27/2474279.html 由于Android项目开源所致,市面上出现了N多安卓软件市场.为 ...

  4. Android实现自动更新功能

    Android实现自动更新功能 Android自动更新的功能可以使用第三方的SDK来实现,但是类似友盟,就不支持x86手机的自动更新,科大讯飞,弹窗是全局的,小米手机就会默认把弹窗权限关掉不允许弹出提 ...

  5. Android应用自动更新功能的实现!

    Android应用自动更新功能的实现!http://blog.csdn.net/android_tutor/article/details/7015986 private static final i ...

  6. Android应用自动更新功能的实现!!!

    自动更新功能的实现原理,就是我们事先和后台协商好一个接口,我们在应用的主Activity里,去访问这个接口,如果需要更新,后台会返回一些数据(比如,提示语:最新版本的url等).然后我们给出提示框,用 ...

  7. Android 软件自动更新功能实现的方法

    相信所有的用户都遇到过软件提醒更新的情况,下面就将实现此功能 首先看一下程序目录结构 步骤: 1.新建一个类UpdateManger,用于显示提示更新 详细出处参考:http://www.jb51.n ...

  8. WinForm应用程序中实现自动更新功能

    WinForm应用程序中实现自动更新功能 编写人:左丘文 2015-4-20 近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因 ...

  9. 【实用篇】Android之应用程序实现自动更新功能

    我个人用的是友盟提供的自动更新组件,因此在这里只描述如何实用友盟提供的组件来完成程序的自动更新,步骤如下: 1.登录友盟官网,点击注册一个友盟账号. 2.注册成功后将会自动进入到添加新应用界面,选择添 ...

随机推荐

  1. Java学习个人备忘录之多线程

    进程:正在进行中的程序(直译). 线程:就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以有多个执行路径,称之为多线程. 一个进程中至少要有一个线程. 开启多个线程是为了同时运行多部分代 ...

  2. 一个例子说明mouseover事件与mouseenter事件的区别

    <html> <head> <meta charset="UTF-8"> <title>haha</title> < ...

  3. lintcode-18-带重复元素的子集

    带重复元素的子集 给定一个可能具有重复数字的列表,返回其所有可能的子集 注意事项 子集中的每个元素都是非降序的 两个子集间的顺序是无关紧要的 解集中不能包含重复子集 样例 如果 S = [1,2,2] ...

  4. python爬虫从入门到放弃(五)之 正则的基本使用(转)

    什么是正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是 事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符”,这个“规则字符” 来表达对字符的一种过滤逻辑. 正则并不是pyth ...

  5. Error:Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"

    (1) 网上下载了一个android应用:死活用不了,查了以下,原来是android studio版本不对,于是把android studio的版本从2.2 升级到3.0,后来发现没法升级,只能下载, ...

  6. jCanvaScript canvas的操作库

    在jcscript.com上下载最新的jCanvaScript.1.5.18.min.js文件  里面有很多关于canvas的方法都已经是封装好了的,只需直接调用,但是要注意调用之前和调用之后都要写: ...

  7. RT-thread内核之对象管理系统

    一.数据结构 1.对象控制块:在include/rtdef.h中定义 /** * Base structure of Kernel object */ struct rt_object { char ...

  8. 【bzoj2699】更新 dp

    题目描述 对于一个数列A[1..N],一种寻找最大值的方法是:依次枚举A[2]到A[N],如果A[i]比当前的A[1]值要大,那么就令A[1]=A[i],最后A[1]为所求最大值.假设所有数都在范围[ ...

  9. Go语言【第十三篇】:Go语言递归函数

    Go语言递归函数 递归,就是在运行的过程中调用自己,语法格式如下: func recursion() { recursion() /* 函数调用自身 */ } func main() { recurs ...

  10. linux系统环境代理设置

    系统上网代理设置: 1.编辑文件/etc/profile,增加如下两行 export http_proxy=http://ip:port export https_proxy=http://ip:po ...