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

Android应用自动更新
本文介绍了一种实现Android应用自动更新的方法。通过服务器上的配置文件,应用程序可以检查是否有新版本可用。文章详细解释了如何解析XML配置文件以获取新版本信息,并展示了如何在设备上检测并显示更新通知。

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

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

 

<update>

2

    <version>2</version>

3

    <name>baidu_xinwen_1.1.0</name>

5

</update>

 

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

 
1public class ParseXmlService
2{
3    publicHashMap<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                elseif (("name".equals(childElement.getNodeName())))
31                {
32                    hashMap.put("name",childElement.getFirstChild().getNodeValue());
33                }
34                //下载地址
35                elseif (("url".equals(childElement.getNodeName())))
36                {
37                    hashMap.put("url",childElement.getFirstChild().getNodeValue());
38                }
39            }
40        }
41        returnhashMap;
42    }
43}

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

 
1/**
2 * 获取软件版本号
3 *
4 * @param context
5 * @return
6 */
7private int getVersionCode(Context context)
8{
9    intversionCode = 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    returnversionCode;
19}

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

处理代码

 
1package com.szy.update;
2  
3import java.io.File;
4import java.io.FileOutputStream;
5import java.io.IOException;
6import java.io.InputStream;
7import java.net.HttpURLConnection;
8import java.net.MalformedURLException;
9import java.net.URL;
10import java.util.HashMap;
11  
12import android.app.AlertDialog;
13import android.app.Dialog;
14import android.app.AlertDialog.Builder;
15import android.content.Context;
16import android.content.DialogInterface;
17import android.content.Intent;
18import android.content.DialogInterface.OnClickListener;
19import android.content.pm.PackageManager.NameNotFoundException;
20import android.net.Uri;
21import android.os.Environment;
22import android.os.Handler;
23import android.os.Message;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.widget.ProgressBar;
27import android.widget.Toast;
28  
29/**
30 *@author coolszy
31 *@date 2012-4-26
33 */
34  
35public 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 */
134private 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     *@
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    privatevoid 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}

效果图
若水工作室
若水工作室
检查模拟器SDCARD是否存在下载文件:
若水工作室

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值