应用升级大致步骤:
检测是否有更新(读取服务器config文件,比对版本号)
若发现高版本则读取更新文件updateinfo.xml获取下载更新相关信息
校验信息确认升级后,下载apk
下载完apk后,进行MD5检验apk的完整性
安装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<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));
}
//检查信息合法性,通过则发送可更新消息
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()主要校验信息的合法性
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)//检测是否可访问
&& versionCode.equals(updateVCode)//config和updateinfoxml文件中版本号是否一致
&& packageName.equals(getPackageName())) {//包名
return true;
}
return false;
}
下载文件到设备需要权限
<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();//创建文件夹
}
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);
}
安装完成后进入应用
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。