应用升级大致步骤:

  1. 检测是否有更新(读取服务器config文件,比对版本号)

  2. 若发现高版本则读取更新文件updateinfo.xml获取下载更新相关信息

  3. 校验信息确认升级后,下载apk

  4. 下载完apk后,进行MD5检验apk的完整性

  5. 安装apk

升级入口

private void upgrade() {		//需要访问网络,避免主线程堵塞		new Thread(){			public void run() {				if(checkUpdate()){//检查更新					handler.sendEmptyMessage(20);//通知界面提示有版本更新				}			};		}.start();	}				private boolean checkUpdate(){				String url = PATH_SERVER + "upgrade/config";		//从config文件读取Version信息,和UpdateInfo.xml文件地址		try {			updateInfoMap = ParseUpdateFile.getConfigInfo(url);		} catch (Exception e) {			e.printStackTrace();		}		//获取当前apk的版本号		PackageInfo packageInfo = null;		try {			packageInfo = MainActivity.this.getPackageManager().getPackageInfo(MainActivity.this.getPackageName(), 0);		} catch (Exception e) {			e.printStackTrace();		}				int updateVCode = Integer.valueOf(updateInfoMap.get("Version"));				//服务器端apk版本高于现在的版本,则读取updateinfo.xml文件		if(updateVCode > packageInfo.versionCode){						url = PATH_SERVER+"upgrade/updateinfo.xml";						try {				updateInfoMap.putAll(ParseXmlUtil.parseXml(url));			} catch (Exception e) {				e.printStackTrace();			}						//输出读取结果			Set
 set = updateInfoMap.keySet(); System.out.println("map.size():"+updateInfoMap.size()); for (Iterator
 iterator = set.iterator(); iterator.hasNext();) { String string = (String) iterator.next(); System.out.println(string + "——>" + updateInfoMap.get(string)); } //检查信息合法性,通过则发送可更新消息 return checkUpdateInfo(updateInfoMap); } return false; }

解析config文件

public static Map
 getConfigInfo(String strURL) throws Exception { Map
 configMap = new HashMap
(); URL url = new URL(strURL); URLConnection conn = url.openConnection(); if (conn == null) { return configMap; } InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while (null != (str=bufferedReader.readLine())) { if (str != null) { if (str.contains("Version=")) { configMap.put("Version", str.substring(str.indexOf("=")+1)); } if (str.contains("VersionServer")) { configMap.put("VersionServer", str.substring(str.indexOf("::")+2)); } } } bufferedReader.close(); return configMap; }

checkUpdateInfo()主要校验信息的合法性

private boolean checkUpdateInfo(Map
 updateInfoMap){ String downloadPath = updateInfoMap.get("DownloadPath"); String packageName = updateInfoMap.get("packageName"); String versionCode = updateInfoMap.get("versionCode"); String updateVCode = updateInfoMap.get("Version"); if (checkUrl(downloadPath)//检测是否可访问 && versionCode.equals(updateVCode)//config和updateinfoxml文件中版本号是否一致 && packageName.equals(getPackageName())) {//包名 return true; } return false; }

下载文件到设备需要权限

private void downLoadAPK(){				new Thread() {			public void run() {								String downLoadPath = updateInfoMap.get("DownloadPath");				String downLoadDir = "/acfg/";								File fileDir = new File(downLoadDir);				if (!fileDir.exists()) {					fileDir.mkdir();//创建文件夹				}								String fileName = downLoadDir + downLoadPath.substring(downLoadPath.lastIndexOf("/")+1);								File file = new File(fileName);				if (file.exists()) {					file.delete();//先删除之前已存在的文件				}								try {					file.createNewFile();										URL url = new URL(downLoadPath);// 构造URL										URLConnection con = url.openConnection();// 打开连接										int contentLength = con.getContentLength();// 获得文件的长度					System.out.println("长度 :" + contentLength);										InputStream is = con.getInputStream();// 输入流										byte[] bs = new byte[1024];// 1K的数据缓冲										int len;// 读取到的数据长度										OutputStream os = new FileOutputStream(fileName);// 输出的文件流					// 开始读取					while ((len = is.read(bs)) != -1) {						os.write(bs, 0, len);					}										// 完毕,关闭所有链接					os.close();					is.close();										//保存文件路径,方便升级时使用					updateInfoMap.put("fileName", fileName);									} catch (Exception e) {					e.printStackTrace();					handler.sendEmptyMessage(22);//下载失败				}				handler.sendEmptyMessage(21);//通知界面下载完成			};		}.start();			}

下载完成后核对apk的MD5值

File file = new File(fileName);String fileMD5 = MD5Util.getMD5OfFile(file);				if (fileMD5.equals(activity.updateInfoMap.get("md5sum"))) {    Toast.makeText(activity, "Download Finished. It's ready to update!", Toast.LENGTH_LONG).show();    activity.update(fileName);}

获取文件的MD5值

        public static String getMD5OfFile(File file) {		String value = null;		FileInputStream in = null;		try {			in = new FileInputStream(file);			MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());			MessageDigest md5 = MessageDigest.getInstance("MD5");			md5.update(byteBuffer);			BigInteger bi = new BigInteger(1, md5.digest());			value = bi.toString(16).toUpperCase(Locale.ENGLISH);//转为大写		} catch (Exception e) {			e.printStackTrace();		} finally {			if (null != in) {				try {					in.close();				} catch (IOException e) {					e.printStackTrace();				}			}		}		return value;	}

安装下载好的apk

private void update(String filePath) {	    Intent intent = new Intent(Intent.ACTION_VIEW);	    intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");	    startActivity(intent);	}

安装时会提示“解析包时出现问题”,经过测试发现是下载到设备的apk文件的权限问题

故而在安装前先修改apk的权限

private void update(String filePath) {				String cmd = "chmod 755 " + filePath;		try {			Runtime.getRuntime().exec(cmd);		} catch (Exception e) {			e.printStackTrace();		}			    Intent intent = new Intent(Intent.ACTION_VIEW);	    intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");	    startActivity(intent);	}

安装完成后进入应用