作者:snowdream email:yanghui1986527#gmail.com qq 群: 529327615
每次下载完整的新安装包,进行覆盖安装。
将新安装包和已经安装的旧安装包进行比对,生成一个差分升级包(patch包)。用户下载patch包后,和已经安装的旧安装包进行合并,生成新安装包,再进行覆盖安装。
在早期的android应用开发中,由于android应用普遍比较小,因此,普遍采用了全量升级方案。简单粗暴,却行之有效。
但是,随着android的发展,android应用功能越来越多,体积越来越大,再综合以下几个因素考虑,全量升级方案逐渐无法满足我们的需求。
1.在国内,随着2g,3g,4g的逐步演进,手机网络越来越快,但有一点事实仍然没有改变:流量很贵,非常不够用。(这个因素不适合wifi用户和土豪用户)
以北京移动为例,最基础套餐,5元30m流量。而最新的微信apk安装包35m。也就是说,如果你选了最基础套餐,你一个月内使用全量升级方案,升级一次微信,流量都不够用。
2.在敏捷开发大行其道的今天,开发者希望尽快将新开发的功能推送到用户面前,并及时得到用户的反馈。恨不能三天一小版,一周一大版。
综合以上因素,开发者必须为用户考虑:省流量,省流量,省流量。
显然,全量升级这种土豪做法已经不再适用,于是,增量升级应运而生。
首先,两句话简单概括增量升级原理:
1.服务端通过比对最新升级包,和当前应用包,生成差分升级包;
2.客户端将差分升级包和当前应用包合并,生成最新升级包。
接下来,简单介绍下增量升级的原理:
1.首先,客户端获取当前应用的version code和应用apk文件的md5值,发送给服务器;
2.服务器根据既定策略,给用户返回更新包信息。
通过md5值没有查询到旧有apk应用信息,返回全量升级包网址,全量升级包md5值;
需要返回patch包,但还没有生成patch包时,后台去生成patch包,并返回全量升级包网址,全量升级包md5值;
需要返回patch包,并且已经生成patch包时,返回patch包网址,patch包md5值,全量升级包网址,全量升级包md5值;
不需要返回patch包,则返回全量升级包网址,全量升级包md5值;
3.客户端根据返回信息进行更新操作。
如果只有全量升级包相关信息,则下载全量升级包,并在校验md5值后,安装更新包;
如果有差分升级包(patch包),则下载差分升级包。校验差分升级包的md5值。如果校验失败,走上面一个步骤。如果校验成功,则将差分升级包和当前版本的apk进行合并操作,生成新的应用包。校验新的应用包md5值。校验通过,这安装这个生成的新应用包。如果校验失败,则走上面一个步骤。
以上只是简单介绍了增量升级的原理,实际应用中还需要细化,考虑更多的场景。
注意: 下载过程中,必须支持断点续传策略。防止网络不畅时,不断重试,造成的流量浪费。
增量升级方案的核心就是使用diff/patch算法来对新旧apk进行diff/patch操作。
在封装hdiffpatch过程中遇到问题,得到作者@sisong的支持和帮助,在此表示感谢。
bsdiff/bspatch和hdiffpatch算法都是开源的,服务端可以根据源文件来进行编译集成。
这里我主要在android客户端的角度,介绍下bsdiff/bspatch和hdiffpatch怎么使用。
在build.gradle文件中自定义jnilib目录
将 <code>app/libs/armeabi-v7a/libbsdiffpatch.so</code> 拷贝到你的工程对应目录下。
将 <code>app/src/main/java/com/github/snowdream/bsdiffpatch</code> 和 <code>app/src/main/java/com/github/snowdream/diffpatch</code> 拷贝到你的工程对应目录下,包名和文件名都不能改变。
在java文件中参考以下代码进行调用。
将 <code>app/libs/armeabi-v7a/libhdiffpatch.so</code> 拷贝到你的工程对应目录下。
将<code>app/src/main/java/com/github/snowdream/hdiffpatch</code> 和 <code>app/src/main/java/com/github/snowdream/diffpatch</code> 拷贝到你的工程对应目录下,包名和文件名都不能改变。
这里我选择高德地图android客户端的两个版本来进行测试。
测试版本: amap_android_v7.7.4.2128_guanwang.apk 和 amap_android_v7.3.0.2036_guanwang.apk (注:版本跨度大,差异大)
对比算法: bsdiffpatch vs hdiffpatch
测试结果:(详见下图)
bsdiffpatch生成的patch包稍小。
两者的diff操作都非常耗资源,耗时间,无法忍受。(当然diff操作一般在服务端进行)
两者的patch操作都比较快。通过大概五次测试,bsdiffpatch的patch操作需要13s左右,而hdiffpatch的patch操作仅仅需要1s左右。
以上结果仅供参考。
测试结论:
bsdiffpatch应用更广泛
hdiffpatch看起来更高效
以上算是比较成熟的增量升级方案了,但是仔细想想,可能还存在一些问题:
1.由于多渠道,多版本造成非常多patch包
2.bs diff/patch算法性能和内存开销太高
第一个问题可以通过服务器策略进行限制。比如,只有最新版5个版本内的升级采用增量升级,其他的仍然采用全量升级。
据说,还有一种更强大的算法,可以解决以上问题。大家有兴趣的话,可以自己去了解。
<a href="https://gist.github.com/9468305/fa8f1307ea4738225fca">crsync-基于rsync rolling算法的文件增量更新.md</a>
<a href="http://bbs.umeng.com/thread-19-1-1.html">友盟增量更新的原理是什么</a>
<a href="http://my.oschina.net/liucundong/blog/160436">android应用增量更新库(smart app updates)</a>
<a href="http://blog.csdn.net/yyh352091626/article/details/50579859">android实现应用的增量更新升级</a>
<a href="https://github.com/smuyyh/incrementallyupdate">https://github.com/smuyyh/incrementallyupdate</a>
<a href="http://blog.csdn.net/hmg25/article/details/8100896">浅析android应用增量升级</a>
<a href="https://github.com/cundong/smartappupdates">https://github.com/cundong/smartappupdates</a>
<a href="https://github.com/sisong/hdiffpatch">https://github.com/sisong/hdiffpatch</a>
<a href="http://www.daemonology.net/bsdiff/">http://www.daemonology.net/bsdiff/</a>
<a href="https://github.com/snowdream/android-diffpatch">https://github.com/snowdream/android-diffpatch</a>