Android 版本更新之增量更新 包含java、.net服务端
2014-04-01 15:58
155 查看
最近有点小忙,上周一整周都在修改其他项目的BUG,无奈博客未更新。对不住各位亲了~
今天给大家带来关于app更新的一种新方式:增量更新。感谢@hmg25编写的文章《浅析android应用增量升级》详细描述了增量更新的原理。简单来说,增量更新步骤如下:
准备新旧两个版本的apk(A,B);
对A,B进行差分比较,并生成差分包(diff(A,B) => patch),同时生成B的MD5;
新apk的合成:B = A + patch,新合成包的MD5和服务端更新下来的MD5进行比对,相同即可安装。
假设A 4m,B 5m,在服务端生成A —> B的差分包为 B-A = C1m(举个例子而已,可能实际变化的部分不止1M),客户端在更新的时候,将文件C下载,C与旧版A合成新的安装包D,校验B和D的MD5,若相同,则安装,否则更新失败。
demo运行过程中,所产生的文件:
在编码代码之前,需要做一些准备工作:
新旧apk(A,B)的准备。在demo中,提供old.apk、new.apk。
差分包生成和合并的jar包。javaxdelta.jar trove.jar。
1. 生成patch文件
主要用到的核心代码:
2、合成差分包
思路:将patch和旧版本文件合成,并比对MD5,若生成文件的MD5与服务器下发的MD5匹配,则提示合成成功,否则删除该文件。
核心代码:
接下来就是最后一步,安装APK。
3、安装apk
注释:
在该demo中,路径都是写死的,在实际应用中,应在上述三个关键方法中,设置路径参数。
差分包的生成、合成都没有写在异步方法里面。为了提高用户体验,应编写相应的异步方法,如run、async等。
差分包的生成写在了客户端,实际应该是放在服务端。如果服务端用java来写,那么很幸运,代码直接复制即可。下面我将提供服务端为.NET的差分包生成方式。其他语言没有做研究,额额。。
4、.NET服务端的.patch文件生成
同样是调用javaxdelta,trove,当然并不是直接调用jar包,首先要将这两个包编译成dll文件,供.NET调用。在这里感谢博客园的一位朋友,详细的讲解了IKVM的使用方法:@xiaotie的博文将java库转换为.net库 在这就不详细介绍了。在转换过程中,若遇到问题,可以给我留言,嘿嘿~~
通过IKVM这个工具,将上述两个jar包转成对应的dll文件:javaxdelta.dll、trove.dll,只有这两个包是不够的,还需要将IKVM.OpenJDK.Core.dll、IKVM.Runtime.dll、IKVM.Runtime.JNI.dll三个类库同时引入,才可以正常编译。
.NET服务端.patch生成代码如下:
通过上述操作,就可以实现增量更新。额额。。文件下载什么的好像还没有加撒~这部分的内容可以直接参考度娘的写法即可了~嘿嘿~
源码下载:Android增量更新
今天给大家带来关于app更新的一种新方式:增量更新。感谢@hmg25编写的文章《浅析android应用增量升级》详细描述了增量更新的原理。简单来说,增量更新步骤如下:
准备新旧两个版本的apk(A,B);
对A,B进行差分比较,并生成差分包(diff(A,B) => patch),同时生成B的MD5;
新apk的合成:B = A + patch,新合成包的MD5和服务端更新下来的MD5进行比对,相同即可安装。
假设A 4m,B 5m,在服务端生成A —> B的差分包为 B-A = C1m(举个例子而已,可能实际变化的部分不止1M),客户端在更新的时候,将文件C下载,C与旧版A合成新的安装包D,校验B和D的MD5,若相同,则安装,否则更新失败。
demo运行过程中,所产生的文件:
在编码代码之前,需要做一些准备工作:
新旧apk(A,B)的准备。在demo中,提供old.apk、new.apk。
差分包生成和合并的jar包。javaxdelta.jar trove.jar。
1. 生成patch文件
主要用到的核心代码:
/** * @param sourceFile 旧版本文件(.apk) * @param targetFile 新版本文件(.apk) * @param output 输出文件(.patch) * */ com.nothome.delta.Delta.compute(File sourceFile, File targetFile, DiffWriter output) throws IOException
/** * 生成差分包:old_new.patch = diff(old.apk, old.apk) * * */ private void createPatch() { try { String sd = Environment.getExternalStorageDirectory().getPath(); String oldFile = sd + "/aDiff/old.apk"; String newFile = sd + "/aDiff/new.apk"; String patchFile = sd + "/aDiff/old_new.patch"; DiffWriter output = null; File sourceFile = null; File targetFile = null; sourceFile = new File(oldFile); targetFile = new File(newFile); output = new GDiffWriter(new DataOutputStream( new BufferedOutputStream(new FileOutputStream(new File( patchFile))))); if (sourceFile.length() > Integer.MAX_VALUE || targetFile.length() > Integer.MAX_VALUE) { System.err .println("source or target is too large, max length is " + Integer.MAX_VALUE); System.err.println("aborting.."); } Delta d = new Delta(); d.compute(sourceFile, targetFile, output); Toast.makeText(getApplicationContext(), "生成完成!", Toast.LENGTH_LONG) .show(); } catch (Exception e) { e.printStackTrace(); } }
2、合成差分包
思路:将patch和旧版本文件合成,并比对MD5,若生成文件的MD5与服务器下发的MD5匹配,则提示合成成功,否则删除该文件。
核心代码:
/** * 合成 * @param sourceFile 旧版本文件 * @param patchFile 更新包 * @param outputFile 新版本文件(生成) * * */ com.nothome.delta.GDiffPatcher.patch(File sourceFile, File patchFile, File outputFile) throws IOException
/** * 合成差分包:new.apk = old.apk + old_new.patch * */ private void mixPatch() { try { String sd = Environment.getExternalStorageDirectory() .getAbsolutePath(); String serviceFile = sd + "/aDiff/new.apk"; String source = sd + "/aDiff/old.apk"; String patch = sd + "/aDiff/old_new.patch"; String target = sd + "/aDiff/mix.apk"; String newMD5 = DiffTool.getMD5(new File(serviceFile)); DiffTool.mergeApk(source, patch, target, newMD5); Toast.makeText(getApplicationContext(), "合成完成!", Toast.LENGTH_LONG) .show(); } catch (Exception e) { e.printStackTrace(); } } private static File mergeFile(final String source, final String patch, String target) throws Exception { GDiffPatcher patcher = new GDiffPatcher(); File deffFile = new File(patch); File updatedFile = new File(target); patcher.patch(new File(source), deffFile, updatedFile); return updatedFile; } public static File mergeApk(final String source, final String patch, final String target, String newApkMd5) throws Exception { File updateFile = mergeFile(source, patch, target); String ufpMd5 = getMD5(updateFile); System.out .println("服务端下发的md5:" + newApkMd5 + ",新合并后的apk MD5:" + ufpMd5); if (ufpMd5 == null || !newApkMd5.equalsIgnoreCase(ufpMd5)) { if (updateFile.exists()) { updateFile.delete(); } throw new Exception("MD5错误,不能成功合并!"); } return updateFile; }
接下来就是最后一步,安装APK。
3、安装apk
/** * 安装apk。 这边路径已经写死,实际应用中,apk路径需要当参数传入 * */ private void installAPK() { File apkfile = new File(Environment.getExternalStorageDirectory() .getAbsolutePath() + "/aDiff/mix.apk"); if (!apkfile.exists()) { return; } Intent i = new Intent(Intent.ACTION_VIEW); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); MainActivity.this.startActivity(i); }
注释:
在该demo中,路径都是写死的,在实际应用中,应在上述三个关键方法中,设置路径参数。
差分包的生成、合成都没有写在异步方法里面。为了提高用户体验,应编写相应的异步方法,如run、async等。
差分包的生成写在了客户端,实际应该是放在服务端。如果服务端用java来写,那么很幸运,代码直接复制即可。下面我将提供服务端为.NET的差分包生成方式。其他语言没有做研究,额额。。
4、.NET服务端的.patch文件生成
同样是调用javaxdelta,trove,当然并不是直接调用jar包,首先要将这两个包编译成dll文件,供.NET调用。在这里感谢博客园的一位朋友,详细的讲解了IKVM的使用方法:@xiaotie的博文将java库转换为.net库 在这就不详细介绍了。在转换过程中,若遇到问题,可以给我留言,嘿嘿~~
通过IKVM这个工具,将上述两个jar包转成对应的dll文件:javaxdelta.dll、trove.dll,只有这两个包是不够的,还需要将IKVM.OpenJDK.Core.dll、IKVM.Runtime.dll、IKVM.Runtime.JNI.dll三个类库同时引入,才可以正常编译。
.NET服务端.patch生成代码如下:
/// <summary> /// 生成差分包 /// </summary> /// <param name="oldApkURL"></param> /// <param name="newApkUrl"></param> /// <param name="patchFileUrl"></param> private bool CreateFile(string oldApkURL, string newApkUrl, string patchFileUrl) { try { com.nothome.delta.DiffWriter output = null; java.io.File sourceFile = null; java.io.File targetFile = null; sourceFile = new java.io.File(oldApkURL); targetFile = new java.io.File(newApkUrl); if (sourceFile.exists() && targetFile.exists()) { output = new com.nothome.delta.GDiffWriter(new java.io.DataOutputStream( new java.io.BufferedOutputStream(new java.io.FileOutputStream(new java.io.File( patchFileUrl))))); if (sourceFile.length() > int.MaxValue || targetFile.length() > int.MaxValue) { } com.nothome.delta.Delta d = new com.nothome.delta.Delta(); d.compute(sourceFile, targetFile, output); return true; } else { this.ShowMessage("源文件不存在!"); return false; } } catch (Exception e) { return false; } }
通过上述操作,就可以实现增量更新。额额。。文件下载什么的好像还没有加撒~这部分的内容可以直接参考度娘的写法即可了~嘿嘿~
源码下载:Android增量更新
相关文章推荐
- Android 版本更新之增量更新 包含java、.net服务端
- android 增量更新之 服务端 附带java 调用示例
- 史上最懒的android版本增量更新插件
- 增量升级(省流量更新)的Java服务端实现
- 【Android增量升级系列_02】 浅谈Android增量更新服务端的实现方法
- 关于消息推送的补充,主要介绍服务端的实现,包含object c 版本 c 版本 java 版本 php 版本 (转)
- [置顶] 最全的增量更新入门 包含linux端和Android
- 增量升级(省流量更新)的Java服务端实现
- Android开发环境搭建全程演示(jdk+eclipse+android sdk包含版本更新)
- 关于android 增量更新的实现
- android客户端和java服务端之间用socket来传输图片
- android 发布版本 自动更新 注意事项
- Android中如何实现版本更新
- 【推荐】《Android应用安全设计及安全编码指导手册》更新到2016年9月1日版本
- android R.java文件丢失或无法更新
- 【Android增量升级系列_01】 浅谈Android增量更新客户端的实现方法
- android R.java文件丢失或无法更新
- Android版本检测\自动更新
- C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新) C#各版本新特性 C#版本和.NET版本以及VS版本的对应关系
- 【Android增量升级系列_01】 浅谈Android增量更新客户端的实现方法