
起初萌芽
既然市面上已经有了大厂微软做后盾的CodePush,还有牛X的开源社区的Pushy,为什么还要自己做热更呢?那是有原因的,首先我们从CodePush热更新进行讲解。
CodePush
- 其增量升级仅仅是针对图片资源的
- 其升级服务器程序并不开源
- 其升级的服务器在美国,国内访问很慢且不稳定
Pushy
- 持续更新,后续用到会进行讲解
React Native的热更新就是下载新RN包替换老RN包,但是这样我们的问题就是每次的全量更新RN包会很大,一个影响app包的体积大小,而是浪费用户的带宽流量。那么我们需要考虑的就是增量更新,要达到增量更新的目的,就需要把老RN包和新RN包的差异性找出来,并且可以将这些差异与老RN包还原出新RN包。bsdiff和bspatch相关技术能实现目标。
何为增量?
一个完整的RN-App通常包含以下几个部分:
- native代码部分(objc/java)
- js代码部分,即RN业务代码、依赖的第三方
- 图片资源部分
这里Native代码的更新,你就别多想了,无法在线升级,只能通过市场升级了。
能进行在线升级的只有js代码部分和图片资源部分,具体到代码部分就是bundle文件和assets文件夹。
针对js代码部分(即bundle文件)的增量指的是,代码改动有多少,增量补丁patch就有多少,哪些没有改动的代码部分是不在补丁范围内的。
针对图片部分(即assets文件夹)的增量指的是,升级补丁包中只包含新增的图片和有改动的图片。
那么在app端,下载升级补丁包,只需要和现在的版本进行合并,就能计算出最新版本的全量包。
总结流程如下:
- 计算增量包:v10(新版本) - v1到v9(旧版本) = 增量包(v1-v10.zip、v2-v10.zip…)
- app根据自己当前的版本(比如v6),下载对应的增量包(v6-v10.zip)
- app中通过 v6(旧版本) + v6-v10.zip(增量包) = 新版本(v10),计算出新版本的全量包
当然这里只是简单的操作,实际情况要复杂的多,因为涉及到Native的代码,以及跨版本更新问题。后续进行详细讲解。
增量算法
assets增量算法,比较简单,就是比对,可以很容易的比较出新增文件和不同文件(使用md5)
bundle文件的增量算法,比较复杂,不过有google写的一个开源库,可以针对大字符串进行diff和path,并且支持java、objc、js等等语言,完全的满足了我们的需求。
只用到2个接口,具体请参考github上的文档
- 生成增量包时候:patch_make(text1, text2) => patches
- app生成全量包时候:patch_apply(patches, text1) => [text2, results]
google开源库地址:https://github.com/bystep15/google-diff-match-patch
关于bsdiff相关操作,另一篇博客bsdiff的使用中讲到.
增量更新的大致流程
1、服务器
使用bsdiff算法将老RN包和新RN包生成一个补丁patch文件,供客户端下载。
2、客户端
下载patch文件,使用bspatch算法将补丁patch文件和老RN包生成一个新的RN包

系统设计和各模块职责

bundle要求的app最小版本
因为js代码要依赖于native代码的,所以,jsbundle对app的版本是有要求的。
假如bundle依赖native的一个新的接口,这个接口在v3.0版本的app中才会发布,如果v2.0版本的app升级了这个bundle,那么必然会报错,严重的可能会导致app的崩溃。
安装包命名规范
1.命名规则:hot_老版本号_新版本号.patched
如:
第一个包,版本号为1,不需要补丁patch文件
第二个包,版本号为2,则与第一个包生成一个补丁文件,命名为hot_1_2.patched
第三个包,版本号为3,则与第一个包生成一个补丁文件,命名为hot_1_3.patched
则与第二个包生成一个补丁文件,命名规则为hot_2_3.patched
第四个包,版本号为4,则与第一个包生成一个补丁文件,命名为hot_1_4.patched
则与第二个包生成一个补丁,命名为hot_2_4.patched
则与第三个包生成一个补丁,命名为hot_3_4.patched
2.服务器接口根据版本号,返回最新的补丁patch文件
如:服务器存在hot_1_2.patched
、hot_1_3.patched
、hot_1_4.patched
、hot_2_3.patched
、hot_2_4.patched
、hot_3_4.patched
等这些补丁文件。
则请求结果如下:
当收到版本号为1的请求时,服务器返回hot_1_4.patched;
当收到版本号为2的请求时,服务器返回hot_2_4.patched;
当收到版本号为3的请求时,服务器返回hot_3_4.patched;
更为复杂的情况,由于我们时混合开发,当牵扯到RN与Native之间的交互发生变更时,我们就不能让热更新发挥作用了,否则会导致崩溃,这里需要做一下逻辑处理。
bundle仓库设计
存储全量bundle和增量patch
目录结构说明

1 | bundle 存放全量bundle和全量assets的目录,里面的文件基本上是使用react-native bundle命令生成的 |
config.json示例
1 | { |
update.json示例
1 | [ |
服务器端设计
参数说明
1 | * bundleV: app中的bundle版本 |
返回结果说明
1 | * status : 本次请求后台是否发生了错误 |
场景一:
能升级,且能升级到最新版
1 | { |
场景二:
无需升级,已经是最新版本
1 | { |
场景三:
能升级,能升级到当前appMinV的最新bundle版本,但不是最新的bundle,想升最新bundle,必须先升app
1 | { |
场景四:
不能升级,已经是当前appMinV的最新bundle,但不是最新的bundle,想升最新bundle,必须先升app
1 | { |
Native端设计
客户端的主要工作就是发请求到服务器询问是否能升级,然后根据返回到信息,下载升级包,解压升级包,安装升级包
过程中要保证下载到文件是正确的(md5校验),要保证补丁安装之后的全量bundle文件是正确的(md5校验)