阳光网驿-企业信息化交流平台【DTC零售连锁全渠道解决方案】

 找回密码
 注册

QQ登录

只需一步,快速开始

扫描二维码登录本站

手机号码,快捷登录

老司机
查看: 1867|回复: 2

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

[复制链接]
  • TA的每日心情
    开心
    2021-8-30 00:00
  • 签到天数: 35 天

    [LV.5]常住居民I

    发表于 2013-7-8 11:04:52 | 显示全部楼层 |阅读模式
    网上看了好多自动升级安装的例子.可能是我没配置好.做起来各种的不爽 虽然代码都大同小异 还是自己做的比较满意
    先说下主要的实现逻辑:在测试服务器上放一个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.主要的业务类:注释都在代理里了

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

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

    1. <SPAN style="FONT-SIZE: 18px">package com.example.updateversion;

    2. import java.io.IOException;
    3. import java.io.InputStream;
    4. import java.util.HashMap;

    5. import org.xmlpull.v1.XmlPullParser;
    6. import org.xmlpull.v1.XmlPullParserException;

    7. import android.util.Xml;

    8. public class ParseXmlService {

    9. public HashMap<String, String> parseXml(InputStream inputStream) {
    10. HashMap<String, String> hashMap = null;
    11. boolean flag = true;
    12. try {
    13. XmlPullParser pullParser = Xml.newPullParser();
    14. pullParser.setInput(inputStream, "UTF-8");
    15. int event = pullParser.getEventType();
    16. while (event != XmlPullParser.END_DOCUMENT) {
    17. switch (event) {
    18. case XmlPullParser.START_DOCUMENT:
    19. hashMap = new HashMap<String, String>();
    20. break;
    21. case XmlPullParser.START_TAG:
    22. flag = true;
    23. String name = pullParser.getName();
    24. if ("VERSIONCODE".equalsIgnoreCase(name) && flag == true) {
    25. hashMap.put("versionCode", pullParser.nextText().trim());
    26. } else if ("FILENAME".equalsIgnoreCase(name) && flag == true) {
    27. hashMap.put("fileName", pullParser.nextText().trim());
    28. } else if ("LOADURL".equalsIgnoreCase(name) && flag == true) {
    29. hashMap.put("loadUrl", pullParser.nextText().trim());
    30. }
    31. break;
    32. case XmlPullParser.END_TAG:
    33. flag = false;
    34. break;
    35. }
    36. event = pullParser.next();
    37. }
    38. } catch (XmlPullParserException e) {
    39. e.printStackTrace();
    40. } catch (IOException e) {
    41. e.printStackTrace();
    42. }
    43. // hashMap = new HashMap<String, String>();
    44. // hashMap.put("versionCode", "2");
    45. // hashMap.put("fileName", "updateversion");
    46. // hashMap.put("loadUrl",
    47. // "http://192.168.1.30:8080/server/updateversion/updateversion.apk");
    48. return hashMap;
    49. }

    50. }
    51. </SPAN>
    复制代码


    3:activity的代码主ui:
    1. package com.example.updateversion;

    2. import android.app.Activity;
    3. import android.os.Bundle;
    4. import android.os.Handler;
    5. import android.view.View;

    6. public class MainActivity extends Activity {
    7. private UpdateVersionService updateVersionService;
    8. private static final String UPDATEVERSIONXMLPATH = "http://192.168.1.30:8080/server/updateversion/version.xml";

    9. @Override
    10. public void onCreate(Bundle savedInstanceState) {
    11. super.onCreate(savedInstanceState);
    12. setContentView(R.layout.activity_main);
    13. // TODO Auto-generated method stub
    14. new Handler().postDelayed(new Runnable() {

    15. @Override
    16. public void run() {
    17. // TODO Auto-generated method stub
    18. updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, MainActivity.this);// 创建更新业务对象
    19. updateVersionService.checkUpdate();// 调用检查更新的方法,如果可以更新.就更新.不能更新就提示已经是最新的版本了
    20. }

    21. }, 2000);// 2秒之后执行

    22. }

    23. /**
    24. * 更新按钮的监听事件
    25. *
    26. * @param view
    27. */
    28. public void updateVersion(View view) {
    29. updateVersionService = new UpdateVersionService(UPDATEVERSIONXMLPATH, this);
    30. updateVersionService.checkUpdate();
    31. }

    32. }
    复制代码
    4:下面是主页面的xml和progress的xml


    1. <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. <TextView
    8. android:layout_width="wrap_content"
    9. android:layout_height="wrap_content"
    10. android:text="@string/version_msg"
    11. android:textSize="30sp"
    12. tools:context=".MainActivity" />

    13. <Button
    14. android:layout_width="wrap_content"
    15. android:layout_height="wrap_content"
    16. android:layout_marginTop="30dp"
    17. android:onClick="updateVersion"
    18. android:text="@string/update" />

    19. </LinearLayout>
    复制代码
    progress:

    1. <?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. <ProgressBar
    7. android:id="@+id/updateProgress"
    8. style="@android:attr/progressBarStyleHorizontal"
    9. android:layout_width="fill_parent"
    10. android:layout_height="wrap_content" />

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

    以后能让自己清楚点再次使用这个例子 把服务器的xml格式也贴上来,新的apk和xml放一个文件夹就行
    切记:如果测试的话,不管新的还是旧的apk 都得打包成apk文件.并且用同一个签名.如果是想在debug情况下使用 可以用(win7)C:\Users\rongsheng\.android目录下的debug.keystore这个签名(两个apk签名要一样),系统自带的签名的密码都是android







    该贴已经同步到 sunwy的微博
    楼主热帖
    启用邀请码注册,提高发帖质量,建设交流社区
  • TA的每日心情
    开心
    2013-8-30 12:37
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2013-7-8 14:47:28 | 显示全部楼层
    j从学习java到能做apk开发,这块入门大概需要多长时间?
    启用邀请码注册,提高发帖质量,建设交流社区
  • TA的每日心情
    开心
    2013-8-30 12:37
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2013-7-8 14:52:18 | 显示全部楼层
    j从学习java到能做apk开发,这块入门大概需要多长时间?
    启用邀请码注册,提高发帖质量,建设交流社区
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    快速回复 返回顶部 返回列表