Fork me on GitHub

bsdiff的使用

最近刚刚做完ReactNative基于微软的CodePush进行热更新,可是发现一个问题就是,如果每次更新太慢,一个原因可能是微软的CodePush的服务器在国外,那么如何不依赖微软的CodePush服务器实现增量更新呢?看另一篇博客ReactNative之增量升级方案,这里主要针对如何实现增量补丁的打包,以及如何将增量包和旧包合并成新包,通过bsdiff技术实现,下面针对Mac、iOS和Android三个平台进行一一讲解。

bsdiff介绍

bsdiff是一种二进制差分工具,有bsdiff和bspatch组成,将oldfile和newfile做二进制数据差分(即bsdiff操作),得到更新部分(patch文件),再与oldfile进行合并(bspatch操作)成newfile。

废话不多说,先撸一遍代码再说。

Mac下使用bsdiff

  • 打开终端安装bsdiff
1
$ brew install bsdiff
  • 使用bsdiff生成xxx.patched补丁文件
1
$ bsdiff ./Desktop/test/hot_old.zip  ./Desktop/test/hot_new.zip ./Desktop/test/hot.patched
  • 使用bspatch生成新包文件
1
2
# 注意这里的文件路径
$ bspatch ./Desktop/test/hot_old.zip ./Desktop/test/hot_new_patch.zip ./Desktop/test/hot.patched
  • 验证生成的新包是否正确,通过md5值是否相同,相同则生成正确
1
2
3
4
5
$ md5 ./Desktop/test/hot_new.zip
MD5 (./Desktop/test/hot_new.zip) = bd6c61e552e913d563bc3b16b82fb994

$ md5 ./Desktop/test/hot_new_patch.zip
MD5 (./Desktop/test/hot_new_patch.zip) = bd6c61e552e913d563bc3b16b82fb994

iOS使用bsdiff进行文件资源增量更新(bsdiff/bspatch)

下载bsdiff bzip2文件

iOS集成(xcode10.2)

  • 新建一个工程,将下载好的bsdiff、bzip2导入工程中,大致内容如下
  • 编译工程,会报如下错误,意料之中,大致原因是因为存在相同的main函数,我们只需要按照提示一步一步修改方法名字就可以了。

   解决办法如下,这里只演示修改一个文件

  • 在编译发现除了main函数重名以外,还有一个错误如下所示

   解决办法如下:我们查看bzip2.cbzip2recover.c,搜索progName字段,发现又是重名了,那么修改即可,这里不做演示,本项目是将bzip2recover.c文件的progName改为progNameRecover

  • 再次编译,恭喜你编译成功了~,不成功你找我。
  • 因为bsdiff为C语言编写,oc引用c语言,需要新建一个.h文件,在.h文件中引用bsdiff.c和bspatch的方法(该方法名是我讲main方法改名后的方法名)
  • 并且还需要在bsdiff.cbspatch.c文件中#include "BsdiffTool.h"
  • 下面进行本地测试,我们本地创建两个文件夹,大致内容如下,然后打包成zip,然后拖入工程中
  • 调用bsdiff方法,生成补丁包patch,项目命名为hot_bsdiff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
生成增量补丁patch包
参数一: 固定字符串
参数二: oldfile文件路径
参数三: newfile文件路径
参数四: 合成patch的文件路径
*/
- (void)bsdiff
{
const char *argv[4];
argv[0] = "bsdiff";

// old path
NSString *oldPath = [NSString stringWithFormat:@"/%@/%@",[NSBundle mainBundle].bundlePath, @"hot_old.zip"];
argv[1] = [oldPath UTF8String];

// new path
NSString *newPath = [NSString stringWithFormat:@"/%@/%@",[NSBundle mainBundle].bundlePath, @"hot_new.zip"];
argv[2] = [newPath UTF8String];

// patched path
argv[3] = [[self createFileWithFileName:@"hot_bsdiff"] UTF8String];

int result = BsdiffUntils_bsdiff(4, argv);
NSLog(@"bsdiff结果:%d",result);
}

此时运行项目,你会发现document路径下会出现一个hot_bsdiff文件,这个文件就是oldfile和newfile文件二进制差分出来的文件,也就是需要更新的文件,但是这个文件不能直接使用,需要我们通过bspatch方法合成新的zip文件。

  • 调用bspatch方法,将hot_old.zip + hot_bsdiff(patch增量包) 生成新包hot_new.zip,项目命名为hot_bspatch_new.zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
根据增量补丁patch包 + 旧包 生成新包
参数一: 为固定字符串
参数二: oldfile文件路径
参数三: oldfile与patch合成zip文件的路径
参数四: 差分出来的patch补丁包文件路径
*/
- (void)bspatch
{
const char *argv[4];
argv[0] = "bspatch";

// old path
NSString *oldPath = [NSString stringWithFormat:@"/%@/%@",[NSBundle mainBundle].bundlePath, @"hot_old.zip"];
argv[1] = [oldPath UTF8String];

// new path
argv[2] = [[self createFileWithFileName:@"hot_bspatch_new.zip"] UTF8String];

// patch path
argv[3] = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"hot_bsdiff"] UTF8String];

int result = BsdiffUntils_bspatch(4, argv);
NSLog(@"bspatch结果:%d",result);
}

运行项目,在对应路径下,就会看到hot_bspatch_new.zip文件,此时解压次安装包,内容如下

至此iOS集成bsdiff完成。

android使用bsdiff

后续更新

参考链接