• 关于android客户端在线版本更新的总结(json源码)


    作为新手,对于这个问题,我直接采用的方法就是网上找源码;互联网是个神奇的东西,特别是像android这样开源的语言(不过话说开源开的有点儿过,平台多元化,苦煞了像我这样靠着它吃饭的程序猿),只要你想研究,总能找到有利用价值的解决方案。

    废话不多说,版本更新一篇文章说清楚,思路是这样:

    1、在android应用每次登录的时候,通过网络访问远程的配置文件(当然版本控制文件可以多种格式,xml、json、甚至txt……依据个人兴趣而定,知道怎么解析就行),确定要不要更新(若版本号改变,那么就更新;版本控制文件由开发者根据版本变化手动修改;我这里采用的json文件写配置)

    2、通过解析版本配置文件,将所得版本号与现有应用的版本号进行比对,判断是否需要下载更新;

    3、当然版本控制文件可以包含新的apk的URL,新版本特性……附加信息;

    4、在提供版本控制文件的同时,还需要服务器安放新版本的apk文件,通过URI指定新版本的apk地址供远程访问下载到本地手机SD卡;

    5、这里要非常注意的一个问题:版本更新需要appkey的统一,旧版本和新版本都需要是已签名的apk,否则安装更新无法通过。(前面几步按部就班就行,我在测试的过程中apk文件下载到本地,可就是安装不上,显示“安装为完成”,然后每次都提示安装更新,就是这个问题,甚是无语。由于是独自作战,这个问题竟然困扰了我好几天,加了那么多的android技术群,发了n遍的“拜求贴”,就是没人反馈我,悲痛欲绝,还是从一篇大拿的博客上找到了问题根源:app key)

    那篇博文如下:http://blog.csdn.net/shimiso/article/details/6440282

    android的客户端更新功能,相信只有做过的才知道其中的辛酸,一要做好断点续传,二要做好数据库的初始化工作,三要做好签名,四要做好版本校验的算法并且能显示动态进度条和百分比。断点续传好做,但是数据库初始化麻烦点,我们的做法是把sqlite库文件直接从raw下拷贝至sd卡中,并设置了sqlite的读取库路径指向它,感觉这样好一点。签名一开始不知道,每次覆盖都提示安装未完成,后来才明白为了保证应用的唯一性,它就像是身份证一样,其他没什么作用,和塞班的签名不是一回事,封装apk必须保证在同一签名文件下才可相互覆盖安装!

    json解析方法:

      String jsonversion = NetworkTool.getContent(VersionUri);
      JSONArray array = new JSONArray(jsonversion);
       // 解析Version网页,获取版本号
      if (array.length() > 0) {
       JSONObject obj = array.getJSONObject(0);
       NowVersion  = obj.getString("verCode");
       }
      } catch (Exception e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }

    上代码:关键类——UpdateActivity.java

    UpdateActivity。java
      1 package com.android.Update;
    2
    3 import android.app.Activity;
    4 import android.app.AlertDialog;
    5 import android.app.Dialog;
    6 import android.app.ProgressDialog;
    7 import android.content.Context;
    8 import android.content.DialogInterface;
    9 import android.content.Intent;
    10 import android.net.Uri;
    11 import android.os.Bundle;
    12 import android.util.Log;
    13 import android.view.Menu;
    14 import android.view.MenuItem;
    15 import android.webkit.URLUtil;
    16 import android.widget.Toast;
    17 import java.io.File;
    18 import java.io.FileInputStream;
    19 import java.io.FileNotFoundException;
    20 import java.io.FileOutputStream;
    21 import java.io.IOException;
    22 import java.io.InputStream;
    23 import java.net.URL;
    24 import java.net.URLConnection;
    25 import java.util.Properties;
    26 import org.json.JSONArray;
    27 import org.json.JSONObject;
    28
    29 public class UpdateActivity extends Activity {
    30 private static final String TAG = "DOWNLOADAPK";
    31 private String PastVersion;//旧版本号
    32 private String NowVersion;//新版本号
    33 public ProgressDialog pBar; //进度条
    34 private String currentFilePath = ""; //文件
    35 //预安装软件的扩展名
    36 private String fileEx="";
    37 private String fileNa="";//软件名称
    38 //APK下载地址
    39 //TODO 这里要自定义
    40 private String strURL="http://open.sina.com.cn/update.apk";
    41 //版本更新配置文件URi
    42 //TODO 这里也是
    43 private String VersionUri ="http://open.sina.com.cn/update.json";
    44 @Override
    45 public void onCreate(Bundle savedInstanceState) {
    46 super.onCreate(savedInstanceState);
    47 setContentView(R.layout.main);
    48 }
    49
    50 @Override
    51 public boolean onCreateOptionsMenu(Menu menu) {
    52 menu.add(Menu.NONE, Menu.FIRST + 1, 5, "检测更新").setIcon(
    53 android.R.drawable.ic_menu_upload);
    54 menu.add(Menu.NONE,Menu.FIRST+2,4,"退出").setIcon(android.R.drawable.ic_menu_delete);
    55 return true;
    56 }
    57
    58 //处理下载URL文件自定义的函数
    59 private void getFile(final String strPath)
    60 {
    61 pBar.show();
    62 try
    63 {
    64 if (strPath.equals(currentFilePath) )
    65 {
    66 getDataSource(strPath);
    67 }
    68 currentFilePath = strPath;
    69 Runnable r = new Runnable()
    70 {
    71 public void run()
    72 {
    73 try
    74 {
    75 getDataSource(strPath);
    76 }
    77 catch (Exception e)
    78 {
    79 Log.e(TAG, e.getMessage(), e);
    80 }
    81 }
    82 };
    83 new Thread(r).start();
    84 }
    85 catch(Exception e)
    86 {
    87 e.printStackTrace();
    88 }
    89 }
    90
    91 /*取得远程文件*/
    92 private void getDataSource(String strPath) throws Exception
    93 {
    94 if (!URLUtil.isNetworkUrl(strPath))
    95 {
    96 Log.d("Tag","error");
    97 }
    98 else
    99 {
    100 /*取得URL*/
    101 URL myURL = new URL(strPath);
    102 /*建立联机*/
    103 URLConnection conn = myURL.openConnection();
    104 conn.connect();
    105 /*InputStream 下载文件*/
    106 InputStream is = conn.getInputStream();
    107 if (is == null)
    108 {
    109 Log.d("tag","error");
    110 throw new RuntimeException("stream is null");
    111 }
    112 /*建立临时文件*/
    113 File myTempFile = File.createTempFile(fileNa, "."+fileEx);
    114 myTempFile.getAbsolutePath();
    115 /*将文件写入临时盘*/
    116 FileOutputStream fos = new FileOutputStream(myTempFile);
    117 byte buf[] = new byte[128];
    118 do
    119 {
    120 int numread = is.read(buf);
    121 if (numread <= 0)
    122 {
    123 break;
    124 }
    125 fos.write(buf, 0, numread);
    126 }while (true);
    127
    128 /*打开文件进行安装*/
    129 openFile(myTempFile);
    130 //openFile(c);
    131 try
    132 {
    133 is.close();
    134 }
    135 catch (Exception ex)
    136 {
    137 Log.d("Tag","error");
    138 Log.e(TAG, "error: " + ex.getMessage(), ex);
    139 }
    140 }
    141 }
    142
    143 /* 在手机上打开文件的method */
    144 private void openFile(File f)
    145 {
    146 pBar.cancel();
    147 Intent intent = new Intent();
    148 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    149 intent.setAction(android.content.Intent.ACTION_VIEW);
    150
    151 /* 调用getMIMEType()来取得MimeType */
    152 String type = getMIMEType(f);
    153 /* 设定intent的file与MimeType */
    154 intent.setDataAndType(Uri.fromFile(f),type);
    155 startActivity(intent);
    156 }
    157
    158 /* 判断文件MimeType的method */
    159 private String getMIMEType(File f)
    160 {
    161 String type="";
    162 String fName=f.getName();
    163 /* 取得扩展名 */
    164 String end=fName.substring(fName.lastIndexOf(".")+1,fName.length()).toLowerCase();
    165
    166 /* 按扩展名的类型决定MimeType */
    167 if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")||end.equals("xmf")||end.equals("ogg")||end.equals("wav"))
    168 {
    169 type = "audio";
    170 }
    171 else if(end.equals("3gp")||end.equals("mp4"))
    172 {
    173 type = "video";
    174 }
    175 else if(end.equals("jpg")||end.equals("gif")||end.equals("png")||end.equals("jpeg")||end.equals("bmp"))
    176 {
    177 type = "image";
    178 }
    179 else if(end.equals("apk"))
    180 {
    181 /* android.permission.INSTALL_PACKAGES */
    182 type = "application/vnd.android.package-archive";
    183 }
    184 else
    185 {
    186 type="*";
    187 }
    188 /*如果无法直接打开,就跳出软件清单给使用者选择 */
    189 if(end.equals("apk"))
    190 {
    191 }
    192 else
    193 {
    194 type += "/*";
    195 }
    196 return type;
    197 }
    198
    199
    200
    201 private void delFile(String strFileName)
    202 {
    203 File myFile = new File(strFileName);
    204 if(myFile.exists())
    205 {
    206 myFile.delete();
    207 }
    208 }
    209
    210 @Override
    211 public boolean onOptionsItemSelected(MenuItem item) {
    212 try {
    213 String jsonversion = NetworkTool.getContent(VersionUri);
    214 Log.d(TAG, "verjson:"+jsonversion);
    215 JSONArray array = new JSONArray(jsonversion);
    216 // 解析Version网页,获取版本号
    217 if (array.length() > 0) {
    218 JSONObject obj = array.getJSONObject(0);
    219 NowVersion = obj.getString("verCode");
    220 }
    221 } catch (Exception e) {
    222 // TODO Auto-generated catch block
    223 e.printStackTrace();
    224 }
    225
    226 // 装载获取当前的版本号
    227 load();
    228
    229 //当有最新版本的时候
    230 Log.d("update", "pastVersion:"+PastVersion+"&&Nowversion:"+NowVersion);
    231 if(PastVersion != null&&!(PastVersion.equals(NowVersion)))
    232 {
    233 save();
    234 Dialog dialog = new AlertDialog.Builder(UpdateActivity.this).setTitle("系统更新")
    235 .setMessage("发现新版本,请更新!")// 设置内容
    236 .setPositiveButton("确定",// 设置确定按钮
    237 new DialogInterface.OnClickListener() {
    238 public void onClick(DialogInterface dialog,
    239 int which) {
    240 pBar = new ProgressDialog(UpdateActivity.this);
    241 pBar.setTitle("正在下载");
    242 pBar.setMessage("请稍候...");
    243 pBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    244 fileEx = strURL.substring(strURL.lastIndexOf(".")+1,strURL.length()).toLowerCase();
    245 fileNa = strURL.substring(strURL.lastIndexOf("/")+1,strURL.lastIndexOf("."));
    246 getFile(strURL);
    247 }
    248 }).setNegativeButton("取消",
    249 new DialogInterface.OnClickListener() {
    250 public void onClick(DialogInterface dialog,
    251 int whichButton) {
    252 // 点击"取消"按钮之后退出程序
    253 }
    254 }).create();// 创建
    255 // 显示对话框
    256 dialog.show();
    257 }
    258 //
    259 else{
    260 save();
    261 Toast.makeText(this, "当前为最新版本", Toast.LENGTH_LONG).show();
    262 }
    263 return false;
    264
    265 }
    266
    267 @Override
    268 public void onOptionsMenuClosed(Menu menu) {
    269 // Toast.makeText(this, "选项菜单关闭了", Toast.LENGTH_LONG).show();
    270 }
    271
    272 @Override
    273 public boolean onPrepareOptionsMenu(Menu menu) {
    274 // Toast.makeText(this,
    275 // "选项菜单显示之前onPrepareOptionsMenu方法会被调用,你可以用此方法来根据打当时的情况调整菜单",
    276 // Toast.LENGTH_LONG).show();
    277
    278 // 如果返回false,此方法就把用户点击menu的动作给消费了,onCreateOptionsMenu方法将不会被调用
    279
    280 return true;
    281
    282 }
    283
    284 boolean load ()
    285 {
    286 Properties properties = new Properties();
    287 try
    288 {
    289 FileInputStream stream = this.openFileInput("Versionfile.cfg");
    290 //读取文件内容
    291 properties.load(stream);
    292 }
    293 catch (FileNotFoundException e)
    294 {
    295 return false;
    296 }
    297 catch(IOException e)
    298 {
    299 return false;
    300 }
    301 PastVersion = String.valueOf(properties.get("Version").toString());
    302 Log.d("UpdateActivity", "Pastversion:"+PastVersion);
    303 return true;
    304 }
    305
    306 boolean save()
    307 {
    308 Properties properties = new Properties();
    309 properties.put("Version", NowVersion);
    310
    311 try
    312 {
    313 FileOutputStream stream = this.openFileOutput("Versionfile.cfg",Context.MODE_WORLD_WRITEABLE);//openFileOutput(第一个参数指定文件名称,指定操作模式)用于把数据输出到文件当中
    314 properties.store(stream,"");
    315 }
    316 catch (FileNotFoundException e)
    317 {
    318 return false;
    319 }
    320 catch(IOException e)
    321 {
    322 return false;
    323 }
    324 return true;
    325 }
    326 }

    关键代码:NetworkTool .java

    NetworkTool.java
     1 package com.android.Update;
    2
    3 import java.io.BufferedReader;
    4 import java.io.InputStream;
    5 import java.io.InputStreamReader;
    6
    7 import org.apache.http.HttpEntity;
    8 import org.apache.http.HttpResponse;
    9 import org.apache.http.client.HttpClient;
    10 import org.apache.http.client.methods.HttpGet;
    11 import org.apache.http.impl.client.DefaultHttpClient;
    12 import org.apache.http.params.HttpConnectionParams;
    13 import org.apache.http.params.HttpParams;
    14 import org.apache.http.util.EncodingUtils;
    15
    16 public class NetworkTool {
    17
    18 /**
    19 * 获取网址内容
    20 * @param url
    21 * @return
    22 * @throws Exception
    23 */
    24 public static String getContent(String url) throws Exception{
    25 StringBuilder sb = new StringBuilder();
    26
    27 HttpClient client = new DefaultHttpClient();
    28 HttpParams httpParams = client.getParams();
    29 //设置网络超时参数
    30 HttpConnectionParams.setConnectionTimeout(httpParams, 3000);
    31 HttpConnectionParams.setSoTimeout(httpParams, 5000);
    32 HttpResponse response = client.execute(new HttpGet(url));
    33 HttpEntity entity = response.getEntity();
    34 if (entity != null) {
    35 InputStream is = entity.getContent();
    36 BufferedReader reader = new BufferedReader(new InputStreamReader(is, "GB2312"), 8192);
    37
    38 String line = null;
    39 while ((line = reader.readLine())!= null){
    40 //line = EncodingUtils.getString(line.getBytes("GB2312"), "UTF-8");
    41 sb.append(line + "\n");
    42 }
    43 reader.close();
    44 }
    45 return sb.toString();
    46 }
    47 }

    json文件:update.json,放在远程服务器

    [{"appname":"Update Client","apkname":"update.apk","apkUrl":"http://open.sina.com.cn/android/update.apk","verCode":"1","verName":"1.0"}]

    有了新版本的应用apk,首先上传签名后的apk至指定的服务器地址(如本例:strURL="http://open.sina.com.cn/update.apk"),然后修改json文件的vercode、vername,注意apk和json的一致!

    附源码:android在线版本更新源代码http://download.csdn.net/detail/dignity568/4168683


     

  • 相关阅读:
    CFree 提示main must return int
    策略模式
    CFree 提示no newline at the end of file
    EEPROM的写入操作解析
    一些关于mic的知识
    一些关于电池的资料
    太阳能电池板日发电量简易计算方法
    ubuntu 下载编译android源代码
    SC44B0的内存地址解析
    RequireJS 2.0 学习笔记一
  • 原文地址:https://www.cnblogs.com/qsl568/p/2415338.html
Copyright © 2020-2023  润新知