• Android应用更新自动检测下载


    由于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         // 实例化一个文档构建器工厂
     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()方法,我们可以获取服务器上应用的版本、文件名以及下载地址。紧接着我们就需要获取到我们手机上应用的版本信息:

     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 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应用更新自动检测下载

    Android应用更新自动检测下载

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

    Android应用更新自动检测下载


    参考代码下载:

     http://files.cnblogs.com/coolszy/UpdateSoftDemo.rar

  • 相关阅读:
    线程安全
    转 接口和抽象类 虚方法 有什么区别
    转 面向对象的三个基本特征
    转载 泛型
    遍历list,字典
    转 拉姆达表达式,委托、匿名方法、Lambda表达式的演进
    int byte转换
    委托,匿名方法
    带参数线程,不带参数线程
    const readonly
  • 原文地址:https://www.cnblogs.com/lr393993507/p/5549009.html
Copyright © 2020-2023  润新知