应用升级大致步骤:

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

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

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

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

安装apk



升级入口

privatevoidupgrade(){//需要访问网络,避免主线程堵塞newThread(){publicvoidrun(){if(checkUpdate()){//检查更新handler.sendEmptyMessage(20);//通知界面提示有版本更新}};}.start();}privatebooleancheckUpdate(){Stringurl=PATH_SERVER+"upgrade/config";//从config文件读取Version信息,和UpdateInfo.xml文件地址try{updateInfoMap=ParseUpdateFile.getConfigInfo(url);}catch(Exceptione){e.printStackTrace();}//获取当前apk的版本号PackageInfopackageInfo=null;try{packageInfo=MainActivity.this.getPackageManager().getPackageInfo(MainActivity.this.getPackageName(),0);}catch(Exceptione){e.printStackTrace();}intupdateVCode=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(Exceptione){e.printStackTrace();}//输出读取结果Set<String>set=updateInfoMap.keySet();System.out.println("map.size():"+updateInfoMap.size());for(Iterator<String>iterator=set.iterator();iterator.hasNext();){Stringstring=(String)iterator.next();System.out.println(string+"——>"+updateInfoMap.get(string));}//检查信息合法性,通过则发送可更新消息returncheckUpdateInfo(updateInfoMap);}returnfalse;}


解析config文件

publicstaticMap<String,String>getConfigInfo(StringstrURL)throwsException{Map<String,String>configMap=newHashMap<String,String>();URLurl=newURL(strURL);URLConnectionconn=url.openConnection();if(conn==null){returnconfigMap;}InputStreaminputStream=conn.getInputStream();InputStreamReaderinputStreamReader=newInputStreamReader(inputStream);BufferedReaderbufferedReader=newBufferedReader(inputStreamReader);Stringstr=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();returnconfigMap;}


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

privatebooleancheckUpdateInfo(Map<String,String>updateInfoMap){StringdownloadPath=updateInfoMap.get("DownloadPath");StringpackageName=updateInfoMap.get("packageName");StringversionCode=updateInfoMap.get("versionCode");StringupdateVCode=updateInfoMap.get("Version");if(checkUrl(downloadPath)//检测是否可访问&&versionCode.equals(updateVCode)//config和updateinfoxml文件中版本号是否一致&&packageName.equals(getPackageName())){//包名returntrue;}returnfalse;}


下载文件到设备需要权限

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

privatevoiddownLoadAPK(){newThread(){publicvoidrun(){StringdownLoadPath=updateInfoMap.get("DownloadPath");StringdownLoadDir="/acfg/";FilefileDir=newFile(downLoadDir);if(!fileDir.exists()){fileDir.mkdir();//创建文件夹}StringfileName=downLoadDir+downLoadPath.substring(downLoadPath.lastIndexOf("/")+1);Filefile=newFile(fileName);if(file.exists()){file.delete();//先删除之前已存在的文件}try{file.createNewFile();URLurl=newURL(downLoadPath);//构造URLURLConnectioncon=url.openConnection();//打开连接intcontentLength=con.getContentLength();//获得文件的长度System.out.println("长度:"+contentLength);InputStreamis=con.getInputStream();//输入流byte[]bs=newbyte[1024];//1K的数据缓冲intlen;//读取到的数据长度OutputStreamos=newFileOutputStream(fileName);//输出的文件流//开始读取while((len=is.read(bs))!=-1){os.write(bs,0,len);}//完毕,关闭所有链接os.close();is.close();//保存文件路径,方便升级时使用updateInfoMap.put("fileName",fileName);}catch(Exceptione){e.printStackTrace();handler.sendEmptyMessage(22);//下载失败}handler.sendEmptyMessage(21);//通知界面下载完成};}.start();}


下载完成后核对apk的MD5值

Filefile=newFile(fileName);StringfileMD5=MD5Util.getMD5OfFile(file);if(fileMD5.equals(activity.updateInfoMap.get("md5sum"))){Toast.makeText(activity,"DownloadFinished.It'sreadytoupdate!",Toast.LENGTH_LONG).show();activity.update(fileName);}


获取文件的MD5值

publicstaticStringgetMD5OfFile(Filefile){Stringvalue=null;FileInputStreamin=null;try{in=newFileInputStream(file);MappedByteBufferbyteBuffer=in.getChannel().map(FileChannel.MapMode.READ_ONLY,0,file.length());MessageDigestmd5=MessageDigest.getInstance("MD5");md5.update(byteBuffer);BigIntegerbi=newBigInteger(1,md5.digest());value=bi.toString(16).toUpperCase(Locale.ENGLISH);//转为大写}catch(Exceptione){e.printStackTrace();}finally{if(null!=in){try{in.close();}catch(IOExceptione){e.printStackTrace();}}}returnvalue;}


安装下载好的apk

privatevoidupdate(StringfilePath){Intentintent=newIntent(Intent.ACTION_VIEW);intent.setDataAndType(Uri.fromFile(newFile(filePath)),"application/vnd.android.package-archive");startActivity(intent);}

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

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

privatevoidupdate(StringfilePath){Stringcmd="chmod755"+filePath;try{Runtime.getRuntime().exec(cmd);}catch(Exceptione){e.printStackTrace();}Intentintent=newIntent(Intent.ACTION_VIEW);intent.setDataAndType(Uri.fromFile(newFile(filePath)),"application/vnd.android.package-archive");startActivity(intent);}

安装完成后进入应用