zoukankan      html  css  js  c++  java
  • Android应用开发笔记(12):Android应用的自动升级、更新模块的实现

    我们看到很多Android应用都具有自动更新功能,用户一键就可以完成软件的升级更新。得益于Android系统的软件包管理和安装机制,这一功能实现起来相当简单,下面我们就来实践一下。首先给出界面效果:

     

    回复wallyell:已经解决,原来是SD卡写入权限问题
    处理这个异常应该在AndroidManifest.xml文件中添加向sd卡写入文件的权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

     

    1. 准备知识 在AndroidManifest.xml里定义了每个Android apk的版本标识:

    1. <manifestxmlns:android="http://schemas.android.com/apk/res/android" 
    2.       package="com.myapp" 
    3.       android:versionCode="1" 
    4.       android:versionName="1.0.0"> 
    5. <application></application> 
    6. </manifest> 


    其中,android:versionCode和android:versionName两个字段分别表示版本代码,版本名称。versionCode是整型数字,versionName是字符串。由于version是给用户看的,不太容易比较大小,升级检查时,可以以检查versionCode为主,方便比较出版本的前后大小。 那么,在应用中如何读取AndroidManifest.xml中的versionCode和versionName呢?可以使用PackageManager的API,参考以下代码:

    1. publicstaticint getVerCode(Context context) { 
    2.         int verCode = -1
    3.         try
    4.             verCode = context.getPackageManager().getPackageInfo( 
    5.                     "com.myapp", 0).versionCode; 
    6.         } catch (NameNotFoundException e) { 
    7.             Log.e(TAG, e.getMessage()); 
    8.         } 
    9.         return verCode; 
    10.     } 
    11.     
    12.     publicstatic String getVerName(Context context) { 
    13.         String verName = ""
    14.         try
    15.             verName = context.getPackageManager().getPackageInfo( 
    16.                     "com.myapp", 0).versionName; 
    17.         } catch (NameNotFoundException e) { 
    18.             Log.e(TAG, e.getMessage()); 
    19.         } 
    20.         return verName;    


    或者在AndroidManifest中将android:versionName="1.2.0"写成android:versionName="@string/app_versionName",然后在values/strings.xml中添加对应字符串,这样实现之后,就可以使用如下代码获得版本名称:

    1. publicstatic String getVerName(Context context) { 
    2.         String verName = context.getResources() 
    3.         .getText(R.string.app_versionName).toString(); 
    4.         return verName; 

    同理,apk的应用名称可以这样获得:

    1. publicstatic String getAppName(Context context) { 
    2.         String verName = context.getResources() 
    3.         .getText(R.string.app_name).toString(); 
    4.         return verName; 

    2. 流程框架

    3. 版本检查 在服务端放置最新版本的apk文件,如:http://localhost/myapp/myapp.apk 同时,在服务端放置对应此apk的版本信息调用接口或者文件,如:http://localhost/myapp/ver.json
    ver.json中的内容为:

    1. [{"appname":"jtapp12","apkname":"jtapp-12-updateapksamples.apk","verName":1.0.1,"verCode":2}] 

    然后,在手机客户端上进行版本读取和检查:

    1. privateboolean getServerVer () { 
    2.         try
    3.             String verjson = NetworkTool.getContent(Config.UPDATE_SERVER 
    4.                     + Config.UPDATE_VERJSON); 
    5.             JSONArray array = new JSONArray(verjson); 
    6.             if (array.length() > 0) { 
    7.                 JSONObject obj = array.getJSONObject(0); 
    8.                 try
    9.                     newVerCode = Integer.parseInt(obj.getString("verCode")); 
    10.                     newVerName = obj.getString("verName"); 
    11.                 } catch (Exception e) { 
    12.                     newVerCode = -1
    13.                     newVerName = ""
    14.                     returnfalse
    15.                 } 
    16.             } 
    17.         } catch (Exception e) { 
    18.             Log.e(TAG, e.getMessage()); 
    19.             returnfalse
    20.         } 
    21.         returntrue
    22.     } 

    比较服务器和客户端的版本,并进行更新操作。

    1. if (getServerVerCode()) { 
    2.          int vercode = Config.getVerCode(this); // 用到前面第一节写的方法  
    3.          if (newVerCode > vercode) { 
    4.              doNewVersionUpdate(); // 更新新版本  
    5.          } else
    6.              notNewVersionShow(); // 提示当前为最新版本  
    7.          } 
    8.      }         

    详细方法:

    1. privatevoid notNewVersionShow() { 
    2.     int verCode = Config.getVerCode(this); 
    3.     String verName = Config.getVerName(this); 
    4.     StringBuffer sb = new StringBuffer(); 
    5.     sb.append("当前版本:"); 
    6.     sb.append(verName); 
    7.     sb.append(" Code:"); 
    8.     sb.append(verCode); 
    9.     sb.append(",/n已是最新版,无需更新!"); 
    10.     Dialog dialog = new AlertDialog.Builder(Update.this).setTitle("软件更新"
    11.             .setMessage(sb.toString())// 设置内容  
    12.             .setPositiveButton("确定",// 设置确定按钮  
    13.                     new DialogInterface.OnClickListener() { 
    14.                         @Override 
    15.                         publicvoid onClick(DialogInterface dialog, 
    16.                                 int which) { 
    17.                             finish(); 
    18.                         } 
    19.                     }).create();// 创建  
    20.     // 显示对话框  
    21.     dialog.show(); 
    22. privatevoid doNewVersionUpdate() { 
    23.     int verCode = Config.getVerCode(this); 
    24.     String verName = Config.getVerName(this); 
    25.     StringBuffer sb = new StringBuffer(); 
    26.     sb.append("当前版本:"); 
    27.     sb.append(verName); 
    28.     sb.append(" Code:"); 
    29.     sb.append(verCode); 
    30.     sb.append(", 发现新版本:"); 
    31.     sb.append(newVerName); 
    32.     sb.append(" Code:"); 
    33.     sb.append(newVerCode); 
    34.     sb.append(", 是否更新?"); 
    35.     Dialog dialog = new AlertDialog.Builder(Update.this
    36.             .setTitle("软件更新"
    37.             .setMessage(sb.toString()) 
    38.             // 设置内容  
    39.             .setPositiveButton("更新",// 设置确定按钮  
    40.                     new DialogInterface.OnClickListener() { 
    41.                         @Override 
    42.                         publicvoid onClick(DialogInterface dialog, 
    43.                                 int which) { 
    44.                             pBar = new ProgressDialog(Update.this); 
    45.                             pBar.setTitle("正在下载"); 
    46.                             pBar.setMessage("请稍候..."); 
    47.                             pBar.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
    48.                             downFile(Config.UPDATE_SERVER + Config.UPDATE_APKNAME); 
    49.                         } 
    50.                     }) 
    51.             .setNegativeButton("暂不更新"
    52.                     new DialogInterface.OnClickListener() { 
    53.                         publicvoid onClick(DialogInterface dialog, 
    54.                                 int whichButton) { 
    55.                             // 点击"取消"按钮之后退出程序  
    56.                             finish(); 
    57.                         } 
    58.                     }).create();// 创建  
    59.     // 显示对话框  
    60.     dialog.show(); 

    4. 下载模块

    注,本部分参考了前人的相关实现,见 http://apps.hi.baidu.com/share/detail/24172508

    1. void downFile(final String url) { 
    2.     pBar.show(); 
    3.     new Thread() { 
    4.         publicvoid run() { 
    5.             HttpClient client = new DefaultHttpClient(); 
    6.             HttpGet get = new HttpGet(url); 
    7.             HttpResponse response; 
    8.             try
    9.                 response = client.execute(get); 
    10.                 HttpEntity entity = response.getEntity(); 
    11.                 long length = entity.getContentLength(); 
    12.                 InputStream is = entity.getContent(); 
    13.                 FileOutputStream fileOutputStream = null
    14.                 if (is != null) { 
    15.                     File file = new File( 
    16.                             Environment.getExternalStorageDirectory(), 
    17.                             Config.UPDATE_SAVENAME); 
    18.                     fileOutputStream = new FileOutputStream(file); 
    19.                     byte[] buf = newbyte[1024]; 
    20.                     int ch = -1
    21.                     int count = 0
    22.                     while ((ch = is.read(buf)) != -1) { 
    23.                         fileOutputStream.write(buf, 0, ch); 
    24.                         count += ch; 
    25.                         if (length > 0) { 
    26.                         } 
    27.                     } 
    28.                 } 
    29.                 fileOutputStream.flush(); 
    30.                 if (fileOutputStream != null) { 
    31.                     fileOutputStream.close(); 
    32.                 } 
    33.                 down(); 
    34.             } catch (ClientProtocolException e) { 
    35.                 e.printStackTrace(); 
    36.             } catch (IOException e) { 
    37.                 e.printStackTrace(); 
    38.             } 
    39.         } 
    40.     }.start(); 

    下载完成,通过handler通知主ui线程将下载对话框取消。

    1. void down() { 
    2.         handler.post(new Runnable() { 
    3.             publicvoid run() { 
    4.                 pBar.cancel(); 
    5.                 update(); 
    6.             } 
    7.         }); 

        

    5. 安装应用

    1. void update() { 
    2.     Intent intent = new Intent(Intent.ACTION_VIEW); 
    3.     intent.setDataAndType(Uri.fromFile(new File(Environment 
    4.             .getExternalStorageDirectory(), Config.UPDATE_SAVENAME)), 
    5.             "application/vnd.android.package-archive"); 
    6.     startActivity(intent); 


    如果你将apk应用发布到market上,那么,你会发现market内建了类似的模块,可以自动更新或者提醒你是否更新应用。那么,对于你自己的应用需要自动更新的话,自己内建一个是不是更加方便了呢?本文提到的代码大多是在UpdateActivity.java中实现,为了能够使更新过程更加友好,可以在最初launcher的Activity中建立一个线程,用来检查服务端是否有更新。有更新的时候就启动UpdateActivity,这样的使用体验更加平滑。
    本文例程源码查看/下载: http://code.google.com/p/androidex/source/browse/trunk/jtapp-12-updateapksamples

    版权归个人所有,转载请注明出处

    http://blog.csdn.net/xjanker2/archive/2011/04/06/6303937.aspx

  • 相关阅读:
    BigDecimal 的用法
    奇葩问题:Invalid bound statement (not found): cn.zss.zsdemo.mapper.RoleMapper.selectByPrimaryKey
    论文速览:MFQE 2.0: A New Approach for Multi-frame Quality Enhancement on Compressed Video
    博文目录
    【DEBUG】ImportError: No module named 'pygal'
    反直觉的三门问题
    一些卷积概念和图解
    MATLAB随手记
    Python3随手记
    论文写作随手记
  • 原文地址:https://www.cnblogs.com/LiaoHao/p/3268517.html
Copyright © 2011-2022 走看看