最近接了个任务,让公司某个App内置的资源文件支持增量升级.(Android/iOS,之前更新资源文件都是下载完整包全量更新)
Goolge了下解决方法,业内普遍的做法是:
1.Google Play与App Store都支持App的增量更新;
2.对于不上架官方市场,又想提供增量更新的App:
Android解决方法:
https://my.oschina.net/liucundong/blog/160436
iOS解决方法:
https://www.jianshu.com/p/3c58760079d9
总结下来,主要是用到了两个库:
bsdiff: https://link.jianshu.com/?t=http://www.daemonology.net/bsdiff/
bzip2: http://www.bzip.org/downloads.html
三个步骤(以Android App):
1.在服务器端,生成新版本apk与旧版本apk的差分包(使用bsdiff算法);
2.在手机客户端,使用已安装的旧版apk与这个差分包,合成为一个新版apk(使用bspatch算法);
3.校验新合成的apk文件是否完成,签名时候和已安装客户端一致,如一致,提示用户安装;
Android与iOS的区别在于Android可以根据apk的增量更新包更新App本身及内置资源文件,iOS则只能根据资源文件的增量包更新内置资源文件.
上述方法的差分文件粒度是字节级别的,考虑到公司现有的资源文件更新机制,将步骤1制作的差分文件粒度修改为文件级别更为合适,搜索了一圈,找到一个Linux下较为合适的解决方案:
https://my.oschina.net/mengshuai/blog/551379
主要用到了rsync命令:
完整的shell代码为:
rsync --dry-run -crnC --out-format="%n" newVersion/ oldVersion/ | grep -v "/$" | xargs -I{} rsync -vR newVersion/./{} patch/
总体思路是先列出差异文件,然后复制到补丁目录:
1.列出差异文件
rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快。
-v 详细模式输出
-c 根据checksum结果过滤文件,而非文件大小和修改时间;
-r 递归地(否则不处理子目录下的文件)
-n 干跑(不对目录造成任何实际影响)
-C 使用和CVS一样的方法自动忽略文件
--out-format 指定要输出要更新的文件信息的格式, 使用%n可以列出newVersion下所有与oldVersion不同的文件的相对路径
注:使用 man rsyncd.conf 可以查看格式:
%b the number of bytes actually transferred
%B the permission bits of the file (e.g. rwxrwxrwt)
%c the total size of the block checksums received for the basis file (only when sending)
%C the full-file MD5 checksum if --checksum is enabled or a file was transferred (only for protocol 30 or
above).
%f the filename (long form on sender; no trailing "/")
%G the gid of the file (decimal) or "DEFAULT"
%h the remote host name (only available for a daemon)
%i an itemized list of what is being updated
%l the length of the file in bytes
%L the string " -> SYMLINK", " => HARDLINK", or "" (where SYMLINK or HARDLINK is a filename)
%m the module name
%M the last-modified time of the file
%n the filename (short form; trailing "/" on dir)
%o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
%p the process ID of this rsync session
%P the module path
%t the current date time
%u the authenticated username or an empty string
%U the uid of the file (decimal)
https://superuser.com/questions/1259494/whats-the-difference-between-n-and-f-in-rsyncs-out-format
grep -v "/$" : grep -v表示反向过滤,"/$"匹配以/结尾的字符串,二者结合则可以过滤掉目录,只显示增量文件路径.
于是下述命令即可将增量文件全部列出来:
rsync --dry-run -crnC --out-format="%n" newVersion/ oldVersion/ | grep -v "/$"
2.复制到补丁目录:
之后将增量文件全部复制到补丁文件夹即可:
此处仍然采用rsync命令,使用 xargs接受上面的输出传递给rsync:
xargs -I{} rsync -vR newVersion/./{} patch/
xargs -I,使用-I指定一个替换字符串{},这个字符串在xargs扩展时会被替换掉
rsync -R 使用相对路径.
注意.经过测试,如果命令写成:
xargs -I{} rsync -vR newVersion/{} patch/
则patch目录下是newVersion目录,newVersion下才是差分文件.