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

作者:coolszy 时间:2022-09-17 09:48:25 

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

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


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

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


public class ParseXmlService
{
 public HashMap<String, String> parseXml(InputStream inStream) throws Exception
 {
   HashMap<String, String> hashMap = new HashMap<String, String>();

// 实例化一个文档构建器工厂
   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   // 通过文档构建器工厂获取一个文档构建器
   DocumentBuilder builder = factory.newDocumentBuilder();
   // 通过文档通过文档构建器构建一个文档实例
   Document document = builder.parse(inStream);
   //获取XML文件根节点
   Element root = document.getDocumentElement();
   //获得所有子节点
   NodeList childNodes = root.getChildNodes();
   for (int j = 0; j < childNodes.getLength(); j++)
   {
     //遍历子节点
     Node childNode = (Node) childNodes.item(j);
     if (childNode.getNodeType() == Node.ELEMENT_NODE)
     {
       Element childElement = (Element) childNode;
       //版本号
       if ("version".equals(childElement.getNodeName()))
       {
         hashMap.put("version",childElement.getFirstChild().getNodeValue());
       }
       //软件名称
       else if (("name".equals(childElement.getNodeName())))
       {
         hashMap.put("name",childElement.getFirstChild().getNodeValue());
       }
       //下载地址
       else if (("url".equals(childElement.getNodeName())))
       {
         hashMap.put("url",childElement.getFirstChild().getNodeValue());
       }
     }
   }
   return hashMap;
 }

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


/**
* 获取软件版本号
*
* @param context
* @return
*/
private int getVersionCode(Context context)
{
 int versionCode = 0;
 try
 {
   // 获取软件版本号,
   versionCode = context.getPackageManager().getPackageInfo("com.szy.update", 0).versionCode;
 } catch (NameNotFoundException e)
 {
   e.printStackTrace();
 }
 return versionCode;
}

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

处理流程
Android应用APP自动更新功能的代码实现

处理代码


package com.szy.update;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

public class UpdateManager
{
 /* 下载中 */
 private static final int DOWNLOAD = 1;
 /* 下载结束 */
 private static final int DOWNLOAD_FINISH = 2;
 /* 保存解析的XML信息 */
 HashMap<String, String> mHashMap;
 /* 下载保存路径 */
 private String mSavePath;
 /* 记录进度条数量 */
 private int progress;
 /* 是否取消更新 */
 private boolean cancelUpdate = false;

private Context mContext;
 /* 更新进度条 */
 private ProgressBar mProgress;
 private Dialog mDownloadDialog;

private Handler mHandler = new Handler()
 {
   public void handleMessage(Message msg)
   {
     switch (msg.what)
     {
     // 正在下载
     case DOWNLOAD:
       // 设置进度条位置
       mProgress.setProgress(progress);
       break;
     case DOWNLOAD_FINISH:
       // 安装文件
       installApk();
       break;
     default:
       break;
     }
   };
 };

public UpdateManager(Context context)
 {
   this.mContext = context;
 }

/**
  * 检测软件更新
  */
 public void checkUpdate()
 {
   if (isUpdate())
   {
     // 显示提示对话框
     showNoticeDialog();
   } else
   {
     Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();
   }
 }

/**
  * 检查软件是否有更新版本
  *
  * @return
  */
 private boolean isUpdate()
 {
   // 获取当前软件版本
   int versionCode = getVersionCode(mContext);
   // 把version.xml放到网络上,然后获取文件信息
   InputStream inStream = ParseXmlService.class.getClassLoader().getResourceAsStream("version.xml");
   // 解析XML文件。 由于XML文件比较小,因此使用DOM方式进行解析
   ParseXmlService service = new ParseXmlService();
   try
   {
     mHashMap = service.parseXml(inStream);
   } catch (Exception e)
   {
     e.printStackTrace();
   }
   if (null != mHashMap)
   {
     int serviceCode = Integer.valueOf(mHashMap.get("version"));
     // 版本判断
     if (serviceCode > versionCode)
     {
       return true;
     }
   }
   return false;
 }

/**
* 获取软件版本号
*
* @param context
* @return
*/
private int getVersionCode(Context context)
{
 int versionCode = 0;
 try
 {
   // 获取软件版本号,对应AndroidManifest.xml下android:versionCode
   versionCode = context.getPackageManager().getPackageInfo("com.szy.update", 0).versionCode;
 } catch (NameNotFoundException e)
 {
   e.printStackTrace();
 }
 return versionCode;
}

/**
  * 显示软件更新对话框
  */
 private void showNoticeDialog()
 {
   // 构造对话框
   AlertDialog.Builder builder = new Builder(mContext);
   builder.setTitle(R.string.soft_update_title);
   builder.setMessage(R.string.soft_update_info);
   // 更新
   builder.setPositiveButton(R.string.soft_update_updatebtn, new OnClickListener()
   {
     @Override
     public void onClick(DialogInterface dialog, int which)
     {
       dialog.dismiss();
       // 显示下载对话框
       showDownloadDialog();
     }
   });
   // 稍后更新
   builder.setNegativeButton(R.string.soft_update_later, new OnClickListener()
   {
     @Override
     public void onClick(DialogInterface dialog, int which)
     {
       dialog.dismiss();
     }
   });
   Dialog noticeDialog = builder.create();
   noticeDialog.show();
 }

/**
  * 显示软件下载对话框
  */
 private void showDownloadDialog()
 {
   // 构造软件下载对话框
   AlertDialog.Builder builder = new Builder(mContext);
   builder.setTitle(R.string.soft_updating);
   // 给下载对话框增加进度条
   final LayoutInflater inflater = LayoutInflater.from(mContext);
   View v = inflater.inflate(R.layout.softupdate_progress, null);
   mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
   builder.setView(v);
   // 取消更新
   builder.setNegativeButton(R.string.soft_update_cancel, new OnClickListener()
   {
     @Override
     public void onClick(DialogInterface dialog, int which)
     {
       dialog.dismiss();
       // 设置取消状态
       cancelUpdate = true;
     }
   });
   mDownloadDialog = builder.create();
   mDownloadDialog.show();
   // 现在文件
   downloadApk();
 }

/**
  * 下载apk文件
  */
 private void downloadApk()
 {
   // 启动新线程下载软件
   new downloadApkThread().start();
 }

/**
  * 下载文件线程
  *
  * @author coolszy
  */
 private class downloadApkThread extends Thread
 {
   @Override
   public void run()
   {
     try
     {
       // 判断SD卡是否存在,并且是否具有读写权限
       if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
       {
         // 获得存储卡的路径
         String sdpath = Environment.getExternalStorageDirectory() + "/";
         mSavePath = sdpath + "download";
         URL url = new URL(mHashMap.get("url"));
         // 创建连接
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.connect();
         // 获取文件大小
         int length = conn.getContentLength();
         // 创建输入流
         InputStream is = conn.getInputStream();

File file = new File(mSavePath);
         // 判断文件目录是否存在
         if (!file.exists())
         {
           file.mkdir();
         }
         File apkFile = new File(mSavePath, mHashMap.get("name"));
         FileOutputStream fos = new FileOutputStream(apkFile);
         int count = 0;
         // 缓存
         byte buf[] = new byte[1024];
         // 写入到文件中
         do
         {
           int numread = is.read(buf);
           count += numread;
           // 计算进度条位置
           progress = (int) (((float) count / length) * 100);
           // 更新进度
           mHandler.sendEmptyMessage(DOWNLOAD);
           if (numread <= 0)
           {
             // 下载完成
             mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
             break;
           }
           // 写入文件
           fos.write(buf, 0, numread);
         } while (!cancelUpdate);// 点击取消就停止下载.
         fos.close();
         is.close();
       }
     } catch (MalformedURLException e)
     {
       e.printStackTrace();
     } catch (IOException e)
     {
       e.printStackTrace();
     }
     // 取消下载对话框显示
     mDownloadDialog.dismiss();
   }
 };

/**
  * 安装APK文件
  */
 private void installApk()
 {
   File apkfile = new File(mSavePath, mHashMap.get("name"));
   if (!apkfile.exists())
   {
     return;
   }
   // 通过Intent安装APK文件
   Intent i = new Intent(Intent.ACTION_VIEW);
   i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
   mContext.startActivity(i);
 }
}

效果图
Android应用APP自动更新功能的代码实现Android应用APP自动更新功能的代码实现

检查模拟器SDCARD是否存在下载文件:Android应用APP自动更新功能的代码实现
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

标签:android,版本更新
0
投稿

猜你喜欢

  • 深入理解Java IO的flush

    2022-01-02 20:05:53
  • Idea运行单个main方法,不编译整个工程的问题

    2021-09-06 09:57:22
  • 简单介绍Android开发中的Activity控件的基本概念

    2022-02-23 23:46:21
  • Java中Lambda表达式的进化之路详解

    2023-04-19 21:17:42
  • Kotlin中的5种单例模式示例详解

    2022-03-01 22:51:58
  • C#中的数组用法详解

    2021-08-19 14:50:17
  • 使用游长编码对字符串压缩 Run Length编码示例

    2022-02-18 06:58:51
  • Maven打包jar包没有主属性问题解决方案

    2023-11-25 06:56:32
  • Android 进程间通信实现原理分析

    2022-01-05 10:27:35
  • C#获取路径的几种方式实例分析

    2023-07-18 22:19:16
  • C#实现json格式转换成对象并更换key的方法

    2021-12-23 00:09:39
  • Android开发手册TextView属性实现效果盘点

    2022-03-10 09:29:53
  • spring boot下 500 404 错误页面处理的方法

    2021-09-03 07:12:36
  • Android生成带圆角的Bitmap图片

    2022-09-08 11:18:19
  • Unity3d 如何更改Button的背景色

    2023-10-02 15:48:39
  • springboot 文件上传大小配置的方法

    2023-08-02 11:49:16
  • 基于java ssm springboot实现选课推荐交流平台系统

    2023-06-30 08:22:25
  • 学习Java HashMap,看这篇就够了

    2023-11-11 11:18:56
  • Android Jetpack库剖析之LiveData组件篇

    2022-08-31 02:08:13
  • Android如何从实现到封装一个MVP详解

    2023-02-12 10:44:40
  • asp之家 软件编程 m.aspxhome.com