您好,登錄后才能下訂單哦!
應(yīng)用升級(jí)大致步驟:
檢測(cè)是否有更新(讀取服務(wù)器config文件,比對(duì)版本號(hào))
若發(fā)現(xiàn)高版本則讀取更新文件updateinfo.xml獲取下載更新相關(guān)信息
校驗(yàn)信息確認(rèn)升級(jí)后,下載apk
下載完apk后,進(jìn)行MD5檢驗(yàn)apk的完整性
安裝apk
升級(jí)入口
private void upgrade() { //需要訪問(wèn)網(wǎng)絡(luò),避免主線程堵塞 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(); } //獲取當(dāng)前apk的版本號(hào) 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")); //服務(wù)器端apk版本高于現(xiàn)在的版本,則讀取updateinfo.xml文件 if(updateVCode > packageInfo.versionCode){ url = PATH_SERVER+"upgrade/updateinfo.xml"; try { updateInfoMap.putAll(ParseXmlUtil.parseXml(url)); } catch (Exception e) { e.printStackTrace(); } //輸出讀取結(jié)果 Set<String> set = updateInfoMap.keySet(); System.out.println("map.size():"+updateInfoMap.size()); for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) { String string = (String) iterator.next(); System.out.println(string + "——>" + updateInfoMap.get(string)); } //檢查信息合法性,通過(guò)則發(fā)送可更新消息 return checkUpdateInfo(updateInfoMap); } return false; }
解析config文件
public static Map<String,String> getConfigInfo(String strURL) throws Exception { Map<String,String> configMap = new HashMap<String, String>(); 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()主要校驗(yàn)信息的合法性
private boolean checkUpdateInfo(Map<String, String> updateInfoMap){ String downloadPath = updateInfoMap.get("DownloadPath"); String packageName = updateInfoMap.get("packageName"); String versionCode = updateInfoMap.get("versionCode"); String updateVCode = updateInfoMap.get("Version"); if (checkUrl(downloadPath)//檢測(cè)是否可訪問(wèn) && versionCode.equals(updateVCode)//config和updateinfoxml文件中版本號(hào)是否一致 && packageName.equals(getPackageName())) {//包名 return true; } return false; }
下載文件到設(shè)備需要權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
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();//創(chuàng)建文件夾 } 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);// 構(gòu)造URL URLConnection con = url.openConnection();// 打開(kāi)連接 int contentLength = con.getContentLength();// 獲得文件的長(zhǎng)度 System.out.println("長(zhǎng)度 :" + contentLength); InputStream is = con.getInputStream();// 輸入流 byte[] bs = new byte[1024];// 1K的數(shù)據(jù)緩沖 int len;// 讀取到的數(shù)據(jù)長(zhǎng)度 OutputStream os = new FileOutputStream(fileName);// 輸出的文件流 // 開(kāi)始讀取 while ((len = is.read(bs)) != -1) { os.write(bs, 0, len); } // 完畢,關(guān)閉所有鏈接 os.close(); is.close(); //保存文件路徑,方便升級(jí)時(shí)使用 updateInfoMap.put("fileName", fileName); } catch (Exception e) { e.printStackTrace(); handler.sendEmptyMessage(22);//下載失敗 } handler.sendEmptyMessage(21);//通知界面下載完成 }; }.start(); }
下載完成后核對(duì)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);//轉(zhuǎn)為大寫(xiě) } 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); }
安裝時(shí)會(huì)提示“解析包時(shí)出現(xiàn)問(wèn)題”,經(jīng)過(guò)測(cè)試發(fā)現(xiàn)是下載到設(shè)備的apk文件的權(quán)限問(wèn)題
故而在安裝前先修改apk的權(quán)限
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); }
安裝完成后進(jìn)入應(yīng)用
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。