增量更新技术源于
Android 4.1
Google Play 引入的一项技术,以实现apk升级节约2/3的流量。Google 把这个功能叫做Smart App Updates
。
增量更新的原理:就是将手机上已安装apk与服务器端最新apk进行二进制对比,得到差分包,用户更新程序时,只需要下载差分包,并在本地使用差分包与已安装apk,合成新版apk。
现在这个功能基本上是所有应用市场必备功能了,在这里我们抛开服务器更新流程,只谈 差分
和 合并
的功能应该如何实现?
bsdiff and bspatch
bsdiff
和 bspatch
是一个创建和应用补丁到二进制文件的工具。
bsdiff
:用于拆分bapatch
:用于合并
在 Ubuntu 和 Mac 上这两个工具都可以在包管理中安装。
Ubuntu:
1 | sudo apt-get install bsdiff |
Mac:
1 | brew install bsdiff |
当然我们也需要源码,因为最终合并的操作是在客户端完成的:http://www.daemonology.net/bsdiff/
bsdiff 用到了 bzip2 这个库:http://www.bzip.org/downloads.html
初体验
在电脑上安装了 bsdiff
和 bspatch
,可以立马来体验一下,因为这个工具是基于二进制的,所以根本不挑文件格式,我这里直接拿我本机的两张图片来测试,且这两张图是毫无关系的两张。
两个工具的参数都是:old file,new file,patch file。
1 | ➜ test tree |
这个时候我们检查一下 image2.png
和 image2-new.png
的 MD5 值。
1 | ➜ test md5 image2.png |
很神奇吧,两个文件MD5一模一样,说明就是同一个文件,这就是增量更新实现方案,站在巨人的肩膀上很轻松就实现了。
移植 Android
其实就把 bsdiff
和 bzlib2
两个库用 ndk 编译,然后 jni 调用即可。
新建一个C项目
具体参见官方文档:向您的项目添加 C 和 C++ 代码
拷贝 bsdiff 和 bzip2 库
将相关库文件拷贝至 cpp
目录
1 | ➜ cpp git:(master) ✗ tree -L 2 |
编写 jni
jni基础相关内容参见之前的文章:Java-写给Android应用开发者的JNI快速入门指北
我们这里通过直接调用 bspatch
main 函数的方式来实现合并查分包的功能。
1 | #include "cn_quickits_patch_library_BsPatch.h" |
java 调用
1 | QPatch.patch(oldFile, newFile, patchFile); |
源码
https://github.com/gavinliu/QPatch
算法原理
尽可能多的利用old文件中已有的内容,尽可能少的加入新的内容来构建new文件,通常的做法是对old文件和new文件做子字符串匹配或使用hash技术,提取公共部分,将new文件中剩余的部分打包成patch包,在Patch阶段中,用copy和insert两个基本操作即可将old文件和patch包合成new文件。
- 对文件中所有字符串形成一个字典;
- 对比两个文件,产生
不同部分
和新增部分
; - 将
不同部分
和新增部分
以及相应的控制字用 zip 压缩成一个 patch 包。
参考:BSDiff算法学习笔记
更多资料
由于 bsdiff
效率不是很高,于是乎出现了下面两种方案,由于篇幅原因就不做介绍了。