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

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

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

[html] view plaincopy

  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方式进行文件的解析:

[java] view plaincopy

  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.         // 实例化一个文档构建器工厂  

  8.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  

  9.         // 通过文档构建器工厂获取一个文档构建器  

  10.         DocumentBuilder builder = factory.newDocumentBuilder();  

  11.         // 通过文档通过文档构建器构建一个文档实例  

  12.         Document document = builder.parse(inStream);  

  13.         //获取XML文件根节点  

  14.         Element root = document.getDocumentElement();  

  15.         //获得所有子节点  

  16.         NodeList childNodes = root.getChildNodes();  

  17.         for (int j = 0; j < childNodes.getLength(); j++)  

  18.         {  

  19.             //遍历子节点  

  20.             Node childNode = (Node) childNodes.item(j);  

  21.             if (childNode.getNodeType() == Node.ELEMENT_NODE)  

  22.             {  

  23.                 Element childElement = (Element) childNode;  

  24.                 //版本号  

  25.                 if ("version".equals(childElement.getNodeName()))  

  26.                 {  

  27.                     hashMap.put("version",childElement.getFirstChild().getNodeValue());  

  28.                 }  

  29.                 //软件名称  

  30.                 else if (("name".equals(childElement.getNodeName())))  

  31.                 {  

  32.                     hashMap.put("name",childElement.getFirstChild().getNodeValue());  

  33.                 }  

  34.                 //下载地址  

  35.                 else if (("url".equals(childElement.getNodeName())))  

  36.                 {  

  37.                     hashMap.put("url",childElement.getFirstChild().getNodeValue());  

  38.                 }  

  39.             }  

  40.         }  

  41.         return hashMap;  

  42.     }  

  43. }  

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

[java] view plaincopy

  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。把获取到的手机上应用版本与服务器端的版本进行比较,应用就可以判断处是否需要更新软件。

处理流程

Android应用自动更新功能代码实现_第1张图片
处理代码

[java] view plaincopy

  1. package com.szy.update;  

  2.   

  3. import java.io.File;  

  4. import java.io.FileOutputStream;  

  5. import java.io.IOException;  

  6. import java.io.InputStream;  

  7. import java.net.HttpURLConnection;  

  8. import java.net.MalformedURLException;  

  9. import java.net.URL;  

  10. import java.util.HashMap;  

  11.   

  12. import android.app.AlertDialog;  

  13. import android.app.Dialog;  

  14. import android.app.AlertDialog.Builder;  

  15. import android.content.Context;  

  16. import android.content.DialogInterface;  

  17. import android.content.Intent;  

  18. import android.content.DialogInterface.OnClickListener;  

  19. import android.content.pm.PackageManager.NameNotFoundException;  

  20. import android.net.Uri;  

  21. import android.os.Environment;  

  22. import android.os.Handler;  

  23. import android.os.Message;  

  24. import android.view.LayoutInflater;  

  25. import android.view.View;  

  26. import android.widget.ProgressBar;  

  27. import android.widget.Toast;  

  28.   

  29. /** 

  30.  *@author coolszy 

  31.  *@date 2012-4-26 

  32.  *@blog http://blog.92coding.com 

  33.  */  

  34.   

  35. public class UpdateManager  

  36. {  

  37.     /* 下载中 */  

  38.     private static final int DOWNLOAD = 1;  

  39.     /* 下载结束 */  

  40.     private static final int DOWNLOAD_FINISH = 2;  

  41.     /* 保存解析的XML信息 */  

  42.     HashMap<String, String> mHashMap;  

  43.     /* 下载保存路径 */  

  44.     private String mSavePath;  

  45.     /* 记录进度条数量 */  

  46.     private int progress;  

  47.     /* 是否取消更新 */  

  48.     private boolean cancelUpdate = false;  

  49.   

  50.     private Context mContext;  

  51.     /* 更新进度条 */  

  52.     private ProgressBar mProgress;  

  53.     private Dialog mDownloadDialog;  

  54.   

  55.     private Handler mHandler = new Handler()  

  56.     {  

  57.         public void handleMessage(Message msg)  

  58.         {  

  59.             switch (msg.what)  

  60.             {  

  61.             // 正在下载  

  62.             case DOWNLOAD:  

  63.                 // 设置进度条位置  

  64.                 mProgress.setProgress(progress);  

  65.                 break;  

  66.             case DOWNLOAD_FINISH:  

  67.                 // 安装文件  

  68.                 installApk();  

  69.                 break;  

  70.             default:  

  71.                 break;  

  72.             }  

  73.         };  

  74.     };  

  75.   

  76.     public UpdateManager(Context context)  

  77.     {  

  78.         this.mContext = context;  

  79.     }  

  80.   

  81.     /** 

  82.      * 检测软件更新 

  83.      */  

  84.     public void checkUpdate()  

  85.     {  

  86.         if (isUpdate())  

  87.         {  

  88.             // 显示提示对话框  

  89.             showNoticeDialog();  

  90.         } else  

  91.         {  

  92.             Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();  

  93.         }  

  94.     }  

  95.   

  96.     /** 

  97.      * 检查软件是否有更新版本 

  98.      *  

  99.      * @return  

  100.      */  

  101.     private boolean isUpdate()  

  102.     {  

  103.         // 获取当前软件版本  

  104.         int versionCode = getVersionCode(mContext);  

  105.         // 把version.xml放到网络上,然后获取文件信息  

  106.         InputStream inStream = ParseXmlService.class.getClassLoader().getResourceAsStream("version.xml");  

  107.         // 解析XML文件。 由于XML文件比较小,因此使用DOM方式进行解析  

  108.         ParseXmlService service = new ParseXmlService();  

  109.         try  

  110.         {  

  111.             mHashMap = service.parseXml(inStream);  

  112.         } catch (Exception e)  

  113.         {  

  114.             e.printStackTrace();  

  115.         }  

  116.         if (null != mHashMap)  

  117.         {  

  118.             int serviceCode = Integer.valueOf(mHashMap.get("version"));  

  119.             // 版本判断  

  120.             if (serviceCode > versionCode)  

  121.             {  

  122.                 return true;  

  123.             }  

  124.         }  

  125.         return false;  

  126.     }  

  127.   

  128. /** 

  129.  * 获取软件版本号 

  130.  *  

  131.  * @param context 

  132.  * @return  

  133.  */  

  134. private int getVersionCode(Context context)  

  135. {  

  136.     int versionCode = 0;  

  137.     try  

  138.     {  

  139.         // 获取软件版本号,对应AndroidManifest.xml下android:versionCode  

  140.         versionCode = context.getPackageManager().getPackageInfo("com.szy.update"0).versionCode;  

  141.     } catch (NameNotFoundException e)  

  142.     {  

  143.         e.printStackTrace();  

  144.     }  

  145.     return versionCode;  

  146. }  

  147.   

  148.     /** 

  149.      * 显示软件更新对话框 

  150.      */  

  151.     private void showNoticeDialog()  

  152.     {  

  153.         // 构造对话框  

  154.         AlertDialog.Builder builder = new Builder(mContext);  

  155.         builder.setTitle(R.string.soft_update_title);  

  156.         builder.setMessage(R.string.soft_update_info);  

  157.         // 更新  

  158.         builder.setPositiveButton(R.string.soft_update_updatebtn, new OnClickListener()  

  159.         {  

  160.             @Override  

  161.             public void onClick(DialogInterface dialog, int which)  

  162.             {  

  163.                 dialog.dismiss();  

  164.                 // 显示下载对话框  

  165.                 showDownloadDialog();  

  166.             }  

  167.         });  

  168.         // 稍后更新  

  169.         builder.setNegativeButton(R.string.soft_update_later, new OnClickListener()  

  170.         {  

  171.             @Override  

  172.             public void onClick(DialogInterface dialog, int which)  

  173.             {  

  174.                 dialog.dismiss();  

  175.             }  

  176.         });  

  177.         Dialog noticeDialog = builder.create();  

  178.         noticeDialog.show();  

  179.     }  

  180.   

  181.     /** 

  182.      * 显示软件下载对话框 

  183.      */  

  184.     private void showDownloadDialog()  

  185.     {  

  186.         // 构造软件下载对话框  

  187.         AlertDialog.Builder builder = new Builder(mContext);  

  188.         builder.setTitle(R.string.soft_updating);  

  189.         // 给下载对话框增加进度条  

  190.         final LayoutInflater inflater = LayoutInflater.from(mContext);  

  191.         View v = inflater.inflate(R.layout.softupdate_progress, null);  

  192.         mProgress = (ProgressBar) v.findViewById(R.id.update_progress);  

  193.         builder.setView(v);  

  194.         // 取消更新  

  195.         builder.setNegativeButton(R.string.soft_update_cancel, new OnClickListener()  

  196.         {  

  197.             @Override  

  198.             public void onClick(DialogInterface dialog, int which)  

  199.             {  

  200.                 dialog.dismiss();  

  201.                 // 设置取消状态  

  202.                 cancelUpdate = true;  

  203.             }  

  204.         });  

  205.         mDownloadDialog = builder.create();  

  206.         mDownloadDialog.show();  

  207.         // 现在文件  

  208.         downloadApk();  

  209.     }  

  210.   

  211.     /** 

  212.      * 下载apk文件 

  213.      */  

  214.     private void downloadApk()  

  215.     {  

  216.         // 启动新线程下载软件  

  217.         new downloadApkThread().start();  

  218.     }  

  219.   

  220.     /** 

  221.      * 下载文件线程 

  222.      *  

  223.      * @author coolszy 

  224.      *@date 2012-4-26 

  225.      *@blog http://blog.92coding.com 

  226.      */  

  227.     private class downloadApkThread extends Thread  

  228.     {  

  229.         @Override  

  230.         public void run()  

  231.         {  

  232.             try  

  233.             {  

  234.                 // 判断SD卡是否存在,并且是否具有读写权限  

  235.                 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))  

  236.                 {  

  237.                     // 获得存储卡的路径  

  238.                     String sdpath = Environment.getExternalStorageDirectory() + "/";  

  239.                     mSavePath = sdpath + "download";  

  240.                     URL url = new URL(mHashMap.get("url"));  

  241.                     // 创建连接  

  242.                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();  

  243.                     conn.connect();  

  244.                     // 获取文件大小  

  245.                     int length = conn.getContentLength();  

  246.                     // 创建输入流  

  247.                     InputStream is = conn.getInputStream();  

  248.   

  249.                     File file = new File(mSavePath);  

  250.                     // 判断文件目录是否存在  

  251.                     if (!file.exists())  

  252.                     {  

  253.                         file.mkdir();  

  254.                     }  

  255.                     File apkFile = new File(mSavePath, mHashMap.get("name"));  

  256.                     FileOutputStream fos = new FileOutputStream(apkFile);  

  257.                     int count = 0;  

  258.                     // 缓存  

  259.                     byte buf[] = new byte[1024];  

  260.                     // 写入到文件中  

  261.                     do  

  262.                     {  

  263.                         int numread = is.read(buf);  

  264.                         count += numread;  

  265.                         // 计算进度条位置  

  266.                         progress = (int) (((float) count / length) * 100);  

  267.                         // 更新进度  

  268.                         mHandler.sendEmptyMessage(DOWNLOAD);  

  269.                         if (numread <= 0)  

  270.                         {  

  271.                             // 下载完成  

  272.                             mHandler.sendEmptyMessage(DOWNLOAD_FINISH);  

  273.                             break;  

  274.                         }  

  275.                         // 写入文件  

  276.                         fos.write(buf, 0, numread);  

  277.                     } while (!cancelUpdate);// 点击取消就停止下载.  

  278.                     fos.close();  

  279.                     is.close();  

  280.                 }  

  281.             } catch (MalformedURLException e)  

  282.             {  

  283.                 e.printStackTrace();  

  284.             } catch (IOException e)  

  285.             {  

  286.                 e.printStackTrace();  

  287.             }  

  288.             // 取消下载对话框显示  

  289.             mDownloadDialog.dismiss();  

  290.         }  

  291.     };  

  292.   

  293.     /** 

  294.      * 安装APK文件 

  295.      */  

  296.     private void installApk()  

  297.     {  

  298.         File apkfile = new File(mSavePath, mHashMap.get("name"));  

  299.         if (!apkfile.exists())  

  300.         {  

  301.             return;  

  302.         }  

  303.         // 通过Intent安装APK文件  

  304.         Intent i = new Intent(Intent.ACTION_VIEW);  

  305.         i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");  

  306.         mContext.startActivity(i);  

  307.     }  

  308. }  

效果图

Android应用自动更新功能代码实现_第2张图片

Android应用自动更新功能代码实现_第3张图片

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

Android应用自动更新功能代码实现_第4张图片


你可能感兴趣的:(Android应用自动更新功能代码实现)