android apk版本自动检测升级,安装

网上看了好多自动升级安装的例子.可能是我没配置好.做起来各种的不爽 虽然代码都大同小异 还是自己做的比较满意

先说下主要的实现逻辑:在测试服务器上放一个xml,用来说明服务器的版本,和新apk的下载地址,运行本地apk的时间.去检测服务器xml里的服务器的版本信息,本地apk的版本信息可以在AndroidManifest.xml中的versionCode拿到.代码是context.getPackageManager().getPackageInfo("com.example.updateversion", 0).0;如果他的版本号比本地的版本号高的话就下载更新服务器上的apk,完了后安装新的apk,这样就实现了自动更新apk的目的,记得发布新的apk的时候一定要修改AndroidManifest.xml中的versionCode,只能搞不能低,然的话就这次可以更新.下次再比对的时候就没法更新了

本例共有3个类文件.一个activity 一个下载的主工具类 一个解析xml的工具类  还有2个布局文件.主布局文件和一个progressbar

1.主要的业务类:注释都在代理里了

[java]  view plain copy
  1. <span style="font-size:18px;">package com.example.updateversion;  
  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.AlertDialog.Builder;  
  14. import android.app.Dialog;  
  15. import android.content.Context;  
  16. import android.content.DialogInterface;  
  17. import android.content.DialogInterface.OnClickListener;  
  18. import android.content.Intent;  
  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.  * 检测安装更新文件的助手类 
  31.  *  
  32.  * @author Administrator 
  33.  *  
  34.  */  
  35. public class UpdateVersionService {  
  36.     private static final int DOWN = 1;// 用于区分正在下载  
  37.     private static final int DOWN_FINISH = 0;// 用于区分下载完成  
  38.     private HashMap<String, String> hashMap;// 存储跟心版本的xml信息  
  39.     private String fileSavePath;// 下载新apk的厨房地点  
  40.     private String updateVersionXMLPath;// 检测更新的xml文件  
  41.     private int progress;// 获取新apk的下载数据量,更新下载滚动条  
  42.     private boolean cancelUpdate = false;// 是否取消下载  
  43.     private Context context;  
  44.     private ProgressBar progressBar;  
  45.     private Dialog downLoadDialog;  
  46.     private Handler handler = new Handler() {// 跟心ui  
  47.   
  48.         @Override  
  49.         public void handleMessage(Message msg) {  
  50.             super.handleMessage(msg);  
  51.             switch ((Integer) msg.obj) {  
  52.             case DOWN:  
  53.                 progressBar.setProgress(progress);  
  54.                 break;  
  55.             case DOWN_FINISH:  
  56.                 Toast.makeText(context, "文件下载完成,正在安装更新", Toast.LENGTH_SHORT).show();  
  57.                 installAPK();  
  58.                 break;  
  59.   
  60.             default:  
  61.                 break;  
  62.             }  
  63.         }  
  64.   
  65.     };  
  66.   
  67.     /** 
  68.      * 构造方法 
  69.      *  
  70.      * @param updateVersionXMLPath 
  71.      *            比较版本的xml文件地址(服务器上的) 
  72.      * @param context 
  73.      *            上下文 
  74.      */  
  75.     public UpdateVersionService(String updateVersionXMLPath, Context context) {  
  76.         super();  
  77.         this.updateVersionXMLPath = updateVersionXMLPath;  
  78.         this.context = context;  
  79.     }  
  80.   
  81.     /** 
  82.      * 检测是否可更新 
  83.      *  
  84.      * @return 
  85.      */  
  86.     public void checkUpdate() {  
  87.         if (isUpdate()) {  
  88.             showUpdateVersionDialog();// 显示提示对话框  
  89.         } else {  
  90.             Toast.makeText(context, "已经是新版本", Toast.LENGTH_SHORT).show();  
  91.         }  
  92.     }  
  93.   
  94.     /** 
  95.      * 更新提示框 
  96.      */  
  97.     private void showUpdateVersionDialog() {  
  98.         // 构造对话框  
  99.         AlertDialog.Builder builder = new Builder(context);  
  100.         builder.setTitle("软件更新");  
  101.         builder.setMessage("检测到新版本,是否下载更新");  
  102.         // 更新  
  103.         builder.setPositiveButton("更新"new OnClickListener() {  
  104.             @Override  
  105.             public void onClick(DialogInterface dialog, int which) {  
  106.                 dialog.dismiss();  
  107.                 // 显示下载对话框  
  108.                 showDownloadDialog();  
  109.             }  
  110.         });  
  111.         // 稍后更新  
  112.         builder.setNegativeButton("稍后更新"new OnClickListener() {  
  113.             @Override  
  114.             public void onClick(DialogInterface dialog, int which) {  
  115.                 dialog.dismiss();  
  116.             }  
  117.         });  
  118.         Dialog noticeDialog = builder.create();  
  119.         noticeDialog.show();  
  120.     }  
  121.   
  122.     /** 
  123.      * 下载的提示框 
  124.      */  
  125.     protected void showDownloadDialog() {  
  126.         {  
  127.             // 构造软件下载对话框  
  128.             AlertDialog.Builder builder = new Builder(context);  
  129.             builder.setTitle("正在更新");  
  130.             // 给下载对话框增加进度条  
  131.             final LayoutInflater inflater = LayoutInflater.from(context);  
  132.             View v = inflater.inflate(R.layout.downloaddialog, null);  
  133.             progressBar = (ProgressBar) v.findViewById(R.id.updateProgress);  
  134.             builder.setView(v);  
  135.             // 取消更新  
  136.             builder.setNegativeButton("取消"new OnClickListener() {  
  137.                 @Override  
  138.                 public void onClick(DialogInterface dialog, int which) {  
  139.                     dialog.dismiss();  
  140.                     // 设置取消状态  
  141.                     cancelUpdate = true;  
  142.                 }  
  143.             });  
  144.             downLoadDialog = builder.create();  
  145.             downLoadDialog.show();  
  146.             // 现在文件  
  147.             downloadApk();  
  148.         }  
  149.   
  150.     }  
  151.   
  152.     /** 
  153.      * 下载apk,不能占用主线程.所以另开的线程 
  154.      */  
  155.     private void downloadApk() {  
  156.         new downloadApkThread().start();  
  157.   
  158.     }  
  159.   
  160.     /** 
  161.      * 判断是否可更新 
  162.      *  
  163.      * @return 
  164.      */  
  165.     private boolean isUpdate() {  
  166.         int versionCode = getVersionCode(context);  
  167.         try {  
  168.             // 把version.xml放到网络上,然后获取文件信息  
  169.             URL url = new URL(updateVersionXMLPath);  
  170.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  171.             conn.setReadTimeout(5 * 1000);  
  172.             conn.setRequestMethod("GET");// 必须要大写  
  173.             InputStream inputStream = conn.getInputStream();  
  174.             // 解析XML文件。  
  175.             ParseXmlService service = new ParseXmlService();  
  176.             hashMap = service.parseXml(inputStream);  
  177.         } catch (Exception e) {  
  178.             e.printStackTrace();  
  179.         }  
  180.         if (null != hashMap) {  
  181.             int serverCode = Integer.valueOf(hashMap.get("versionCode"));  
  182.             // 版本判断  
  183.             if (serverCode > versionCode) {  
  184.                 Toast.makeText(context, "新版本是: " + serverCode, Toast.LENGTH_SHORT).show();  
  185.                 return true;  
  186.             }  
  187.         }  
  188.         return false;  
  189.   
  190.     }  
  191.   
  192.     /** 
  193.      * 获取当前版本和服务器版本.如果服务器版本高于本地安装的版本.就更新 
  194.      *  
  195.      * @param context2 
  196.      * @return 
  197.      */  
  198.     private int getVersionCode(Context context2) {  
  199.         int versionCode = 0;  
  200.         try {  
  201.             // 获取软件版本号,对应AndroidManifest.xml下android:versionCode  
  202.             versionCode = context.getPackageManager().getPackageInfo("com.example.updateversion"0).versionCode;  
  203.             Toast.makeText(context, "当前版本是: " + versionCode, Toast.LENGTH_SHORT).show();  
  204.         } catch (NameNotFoundException e) {  
  205.             e.printStackTrace();  
  206.         }  
  207.         return versionCode;  
  208.   
  209.     }  
  210.   
  211.     /** 
  212.      * 安装apk文件 
  213.      */  
  214.     private void installAPK() {  
  215.         File apkfile = new File(fileSavePath, hashMap.get("fileName") + ".apk");  
  216.         if (!apkfile.exists()) {  
  217.             return;  
  218.         }  
  219.         // 通过Intent安装APK文件  
  220.         Intent i = new Intent(Intent.ACTION_VIEW);  
  221.         System.out.println("filepath=" + apkfile.toString() + "  " + apkfile.getPath());  
  222.         i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  223.         i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");  
  224.         context.startActivity(i);  
  225.         android.os.Process.killProcess(android.os.Process.myPid());// 如果不加上这句的话在apk安装完成之后点击单开会崩溃  
  226.   
  227.     }  
  228.   
  229.     /** 
  230.      * 卸载应用程序(没有用到) 
  231.      */  
  232.     public void uninstallAPK() {  
  233.         Uri packageURI = Uri.parse("package:com.example.updateversion");  
  234.         Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);  
  235.         context.startActivity(uninstallIntent);  
  236.   
  237.     }  
  238.   
  239.     /** 
  240.      * 下载apk的方法 
  241.      *  
  242.      * @author rongsheng 
  243.      *  
  244.      */  
  245.     public class downloadApkThread extends Thread {  
  246.         @Override  
  247.         public void run() {  
  248.             // TODO Auto-generated method stub  
  249.             super.run();  
  250.             try {  
  251.                 // 判断SD卡是否存在,并且是否具有读写权限  
  252.                 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
  253.                     // 获得存储卡的路径  
  254.                     String sdpath = Environment.getExternalStorageDirectory() + "/";  
  255.                     fileSavePath = sdpath + "download";  
  256.                     URL url = new URL(hashMap.get("loadUrl"));  
  257.                     // 创建连接  
  258.                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  259.                     conn.setReadTimeout(5 * 1000);// 设置超时时间  
  260.                     conn.setRequestMethod("GET");  
  261.                     conn.setRequestProperty("Charser""GBK,utf-8;q=0.7,*;q=0.3");  
  262.                     // 获取文件大小  
  263.                     int length = conn.getContentLength();  
  264.                     // 创建输入流  
  265.                     InputStream is = conn.getInputStream();  
  266.   
  267.                     File file = new File(fileSavePath);  
  268.                     // 判断文件目录是否存在  
  269.                     if (!file.exists()) {  
  270.                         file.mkdir();  
  271.                     }  
  272.                     File apkFile = new File(fileSavePath, hashMap.get("fileName") + ".apk");  
  273.                     FileOutputStream fos = new FileOutputStream(apkFile);  
  274.                     int count = 0;  
  275.                     // 缓存  
  276.                     byte buf[] = new byte[1024];  
  277.                     // 写入到文件中  
  278.                     do {  
  279.                         int numread = is.read(buf);  
  280.                         count += numread;  
  281.                         // 计算进度条位置  
  282.                         progress = (int) (((float) count / length) * 100);  
  283.                         // 更新进度  
  284.                         Message message = new Message();  
  285.                         message.obj = DOWN;  
  286.                         handler.sendMessage(message);  
  287.                         if (numread <= 0) {  
  288.                             // 下载完成  
  289.                             // 取消下载对话框显示  
  290.                             downLoadDialog.dismiss();  
  291.                             Message message2 = new Message();  
  292.                             message2.obj = DOWN_FINISH;  
  293.                             handler.sendMessage(message2);  
  294.                             break;  
  295.                         }  
  296.                         // 写入文件  
  297.                         fos.write(buf, 0, numread);  
  298.                     } while (!cancelUpdate);// 点击取消就停止下载.  
  299.                     fos.close();  
  300.                     is.close();  
  301.                 }  
  302.             } catch (MalformedURLException e) {  
  303.                 e.printStackTrace();  
  304.             } catch (IOException e) {  
  305.                 e.printStackTrace();  
  306.             }  
  307.   
  308.         }  
  309.   
  310.     }  
  311. }  
  312. </span>  


2:解析工具类,能做到自动升级的地步,xml解析就不用再注释了吧:

[java]  view plain copy
  1. <span style="font-size:18px;">package com.example.updateversion;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.util.HashMap;  
  6.   
  7. import org.xmlpull.v1.XmlPullParser;  
  8. import org.xmlpull.v1.XmlPullParserException;  
  9.   
  10. import android.util.Xml;  
  11.   
  12. public class ParseXmlService {  
  13.   
  14.     public HashMap<String, String> parseXml(InputStream inputStream) {  
  15.         HashMap<String, String> hashMap = null;  
  16.         boolean flag = true;  
  17.         try {  
  18.             XmlPullParser pullParser = Xml.newPullParser();  
  19.             pullParser.setInput(inputStream, "UTF-8");  
  20.             int event = pullParser.getEventType();  
  21.             while (event != XmlPullParser.END_DOCUMENT) {  
  22.                 switch (event) {  
  23.                 case XmlPullParser.START_DOCUMENT:  
  24.                     hashMap = new HashMap<String, String>();  
  25.                     break;  
  26.                 case XmlPullParser.START_TAG:  
  27.                     flag = true;  
  28.                     String name = pullParser.getName();  
  29.                     if ("VERSIONCODE".equalsIgnoreCase(name) && flag == true) {  
  30.                         hashMap.put("versionCode", pullParser.nextText().trim());  
  31.                     } else if ("FILENAME".equalsIgnoreCase(name) && flag == true) {  
  32.                         hashMap.put("fileName", pullParser.nextText().trim());  
  33.                     } else if ("LOADURL".equalsIgnoreCase(name) && flag == true) {  
  34.                         hashMap.put("loadUrl", pullParser.nextText().trim());  
  35.                     }  
  36.                     break;  
  37.                 case XmlPullParser.END_TAG:  
  38.                     flag = false;  
  39.                     break;  
  40.                 }  
  41.                 event = pullParser.next();  
  42.             }  
  43.         } catch (XmlPullParserException e) {  
  44.             e.printStackTrace();  
  45.         } catch (IOException e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.         // hashMap = new HashMap<String, String>();  
  49.         // hashMap.put("versionCode", "2");  
  50.         // hashMap.put("fileName", "updateversion");  
  51.         // hashMap.put("loadUrl",  
  52.         // "http://192.168.1.30:8080/server/updateversion/updateversion.apk");  
  53.         return hashMap;  
  54.     }  
  55.   
  56. }  
  57. </span>  


3:activity的代码主ui:

[java]  view plain copy
  1. <span style="font-size:18px;">package com.example.updateversion;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.view.View;  
  7.   
  8. public class MainActivity extends Activity {  
  9.     private UpdateVersionService updateVersionService;  
  10.     private static final String UPDATEVERSIONXMLPATH = "http://192.168.1.30:8080/server/updateversion/version.xml";  
  11.   
  12.     @Override  
  13.     public void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         // TODO Auto-generated method stub  
  17.         new Handler().postDelayed(new Runnable() {  
  18.   
  19.             @Override  
  20.             public void run() {  
  21.                 // TODO Auto-generated method stub  
  22.                 updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, MainActivity.this);// 创建更新业务对象  
  23.                 updateVersionService.checkUpdate();// 调用检查更新的方法,如果可以更新.就更新.不能更新就提示已经是最新的版本了  
  24.             }  
  25.   
  26.         }, 2000);// 2秒之后执行  
  27.   
  28.     }  
  29.   
  30.     /** 
  31.      * 更新按钮的监听事件 
  32.      *  
  33.      * @param view 
  34.      */  
  35.     public void updateVersion(View view) {  
  36.         updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, this);  
  37.         updateVersionService.checkUpdate();  
  38.     }  
  39.   
  40. }  
  41. </span>  


4:下面是主页面的xml和progress的xml

页面:

[java]  view plain copy
  1. <span style="font-size:18px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:gravity="center_vertical|center_horizontal"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <TextView  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:text="@string/version_msg"  
  12.         android:textSize="30sp"  
  13.         tools:context=".MainActivity" />  
  14.   
  15.     <Button  
  16.         android:layout_width="wrap_content"  
  17.         android:layout_height="wrap_content"  
  18.         android:layout_marginTop="30dp"  
  19.         android:onClick="updateVersion"  
  20.         android:text="@string/update" />  
  21.   
  22. </LinearLayout></span>  


progress:

[java]  view plain copy
  1. <span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <ProgressBar  
  8.         android:id="@+id/updateProgress"  
  9.         style="@android:attr/progressBarStyleHorizontal"  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content" />  
  12.   
  13. </LinearLayout></span>  


以上就是整个程序的代码了 发布新版本只需要修改AndroidManifest.xml文件中的versionCode的值,一定要比升级之前的版本高,那个versionName在本例中没有什么实际意义,主要是versioncode,如果想在ui上看的清楚一点的话 可以经string.xml中的version_msg 标明版本号.这样在ui上就能看到当前的版本了

以后能让自己清楚点再次使用这个例子 把服务器的xml格式也贴上来,新的apk和xml放一个文件夹就行

[html]  view plain copy
  1. <span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>  
  2. <VERSION>  
  3.     <VERSIONCODE>2</VERSIONCODE>  
  4.     <FILENAME>updateversion</FILENAME>  
  5.     <LOADURL>http://192.168.1.30:8080/server/updateversion/updateversion.apk  
  6.     </LOADURL>  
  7. </VERSION></span>  

切记:如果测试的话,不管新的还是旧的apk 都得打包成apk文件.并且用同一个签名.如果是想在debug情况下使用 可以用(win7)C:\Users\rongsheng\.android目录下的debug.keystore这个签名(两个apk签名要一样),系统自带的签名的密码都是android


你可能感兴趣的:(android apk版本自动检测升级,安装)