此文参考何明桂的文章:http://blog.csdn.net/hmg25/article/details/8100896,不过原文中有些步骤太过简略,一句带过,相信很多同学是没那么容易走完全程的,花了一下午研究了下,特此记录,同时希望能帮到需要帮助的同学。
增量升级的原理
首先将应用的旧版本Apk与新版本Apk做差分,得到更新的部分的补丁,例如旧版本的APK有5M,新版的有8M,更新的部分则可能只有3M左右(这里需要说明的是,得到的差分包大小并不是简单的相减,因为其实需要包含一些上下文相关的东西),使用差分升级的好处显而易见,那么你不需要下载完整的8M文件,只需要下载更新部分就可以,而更新部分可能只有3、4M,可以很大程度上减少流量的损失。
在用户下载了差分包之后,需要在手机端将他们组合起来。可以参考的做法是先将手机端的旧版本软件(多半在/data/下),复制到SD卡或者cache中,将它们和之前的差分patch进行组合,得到一个新版本的apk应用,如果不出意外的话,这个生成的apk和你之前做差分的apk是一致的。
增量升级的操作
在了解基本的原理之后,我们来逐步解决其中的各个难点。首先是差分包patch的生成。
android中提供我们用来制作差分增量升级包的工具,"bsdiff",这是一个很牛X开源的二进制差分工具.相关的介绍
传送门
相关的代码
地址 或者在android的代码目录下 \external\bsdiff
bsdiff是二进制差分工具,其对应的bspatch是相应的补丁合成工具
需要注意的是增量升级的补丁包,是需要在服务器端,即PC端完成,大致流程如,制作补丁时调用bsdiff函数,根据两个不同版本的二进制文件,生成补丁文件。
将生成的补丁包 xx.patch放置在升级服务器上,供用户下载升级,对应多版本需要对不同的版本进行差分,对于版本跨度较大的,建议整包升级。
用户在下载了 xx.patch补丁包后,需要用到补丁所对应的apk,即原来系统安装的旧版本apk和补丁合成的bspatch工具。系统旧版本的apk可以通过copy系统data/app目录下的apk文件获取,而补丁合成的bspatch可以通过将bspatch源码稍作修改,封装成一个so库,供手机端调用。
和差分时的参数一样。合成新的apk便可以用于安装。
以上只是简单的操作原理,增量升级还涉及很多其他方面,例如,升级补丁校验等问题,可以参考android源码中bootable\recovery\applypatch的相关操作,本文只是浅析,在此不表。
实验
多说无益,实践才是王道。下面就来简单实践一下,检测之前理论的正确性。
下载实验包 (
http://download.csdn.net/detail/hmg25/4676737),解压后文件如下
以附带的iReader来做测试,在shell进入test\bsdiff4.3-win32文件夹,并下运行命令: 原来的apk(2.94M),新版本的(3.24M),得到的patch文件为1.77M,用户需要下载的就只是1.77M,流量节省了很多。
下面先在电脑端将他们合并。
=============================================原文===================================
下面我们在手机端合成看看,将根目录下的bspatch(此为手机端运行的)、iReader1.6.2.0(v35).apk 和ireader.patch ,通过adb push到你有权限操作的目录,最好是在/sdcard/下,然后设置bspatch的执行权限,重复操作上述命令,可以合成新版本的apk,稍后安装查看验证版本即可,不详述。
=========================================================================================
上述原文中有几点不是很清楚,或者错误的地方。
首先,上述三个文件不要拷到/sdcard下,sdcard下的文件的执行权限是会被安卓系统拒绝的,哪怕设置了文件的执行权限,所以我是复制到data目录下的。
然后,接下来的问题是怎么在手机端调用执行这个命令。很自然的我们想到了adb shell这个终端工具。
在shell终端执行上述命令时,大家肯定会得到这个结果sh : not found ,解决办法是原命令需要小修改:/data/bspatch iReader1.6.2.0v35.apk new.apk ireader.patch 区别就是bspatch需要指定全目录名(ps,注意
iReader1.6.2.0v35.apk 文件名区别,v35的小括号去掉了,shell命令中小括号会报错,所以改了文件名)
OK,这样子在手机端合成新版本也实现了,然后最后的一步就是封装成lib包供代码调用。大部分人包括原文章主人可能都会封装成.so文件然后通过jni调用来实现吧,这种方式应该是OK的,不过通过上面的步骤我觉得不用JNI,直接在安卓代码中执行上述的adb shell命令不知道是否可行,未完待续,有时间试一下。