热更新原理
react-native 的程序实际上是原生的模块+JS和图片资源模块,热更新,就是更新其中的js和图片资源。
安卓程序把它名字命名为zip解压后可以清楚的看到其中的bundle文件和资源文件
热更新的方法
热更新又分为全量更新和增量更新。
全量更新是直接去服务器抓取你上传的ppk文件,下载下来,直接覆盖本地的ppk文件。
增量更新是使用了bsdiff算法,用来比对两者bundle之间的区别,然后只修改不一样的地方。
启动程序的时候,会发一个请求给服务器,询问我需不需要更新
URL: http://update.reactnative.cn/api/checkUpdate/${key}
抓包也好,看源码也好,结论就是使用的是这个请求带上自己热更新json的key值,用来匹配你的app
{
"upToDate": true,
"ok": 1
}
这个是服务器返回给我的值,如果是已经是最新的版本了,就会返回upToDate给我。
{
"expired": true,
"downloadUrl":'xxx',
"ok": 1
}
如果是需要硬版本更新了,就会返回一个expired的给我,顺便给我一个downloadUrl(随便写的,具体可能不是这个名字,懒的再去删版本看了)的参数,当然这个参数是我在他家官网配置的,就是我新版本的下载地址。
这个时候,如果是需要热更新了,根据当前版本[email protected]
的大量数据试验情况来看,返回格式无非就两种,虽然源码里有第三种
{
"update": true,
"hash": "FppJ-yU8-_bvYJe5Sg5_opUp_eFH",
"name": "0.2.1",
"description": "test",
"metaInfo": "0.2.1",
"updateUrl": "http://update-packages.reactnative.cn/FppJ-yU8-_bvYJe5Sg5_opUp_eFH?e=1483510148&token=made75kGFhOozkiRfa7LK_E1xG1pLOnhW8fhbnev:t2YXoxZZXQImvvyHH1hdrnNNRmQ=",
"pdiffUrl": "http://update-packages.reactnative.cn/lpKbEZnU6_T-mvwZGfzIQby489Bm-FppJ-yU8-_bvYJe5Sg5_opUp_eFH.pdiff?e=1483510148&token=made75kGFhOozkiRfa7LK_E1xG1pLOnhW8fhbnev:YBI4sdIEr30wa1DHV4xnMUlI1bU=",
"ok": 1
}
update为true代表我需要热更新,其中有个参数叫updateUrl,这个参数提供的地址就是全量更新的地址,会把我整个bundle都下载下来。
还有一个参数叫pdiffUrl,这个就是增量更新,我会去下载一个pdiff文件,然后你检测会发现,在安卓情况下,你的cpu已经跑起来了,后台程序数据涨起来了,但是流量没动,因为走的是内部计算,测试了一下发现在不同的手机上表现也不一样。
酷派A8930:120S
ViVioX7:90S
小米5:75S。
iphone全系手机1S-5S之间。(目测不是一个人写的代码,或者是安卓读写的线程出了某些问题,仅仅是猜测)
以上时间都是单单是计算时间,因为下载增量更新那几十K也就1S的事情。
关于服务器是否返回pdiffUrl的情况我还是不能推算出官方的原理,因为同样的一个包,有的时候它会返回pdiffUrl,有的时候却只有updateUrl,不过好在不管什么情况下,都有updateUrl,那么我们就可以利用这个点,把不必要的等待给改掉。
比如我流量很多,我不想让我的安卓机器等待100S,又不想后台静默更新,那就直接改源码,好在源码找的很快,修改更是容易。
export async function downloadUpdate(options) {
if (!options.update) {
return;
}
if (options.diffUrl) {
await HotUpdate.downloadPatchFromPpk({
updateUrl: options.diffUrl,
hashName: options.hash,
originHashName: currentVersion,
});
} else if (options.pdiffUrl) {
await HotUpdate.downloadPatchFromPackage({
updateUrl: options.pdiffUrl,
hashName: options.hash,
});
} else {
await HotUpdate.downloadUpdate({
updateUrl: options.updateUrl,
hashName: options.hash,
});
}
return options.hash;
}
这个就是它判断是否走增量更新的代码,其中diffUrl我从来没见到过,所以不动逻辑,所以很简单,把增量和全量调换个顺序就OK了
export async function downloadUpdate(options) {
if (!options.update) {
return;
}
if (options.diffUrl) {
await HotUpdate.downloadPatchFromPpk({
updateUrl: options.diffUrl,
hashName: options.hash,
originHashName: currentVersion,
});
} else if (options.updateUrl) {
await HotUpdate.downloadUpdate({
updateUrl: options.updateUrl,
hashName: options.hash,
});
} else {
await HotUpdate.downloadPatchFromPackage({
updateUrl: options.pdiffUrl,
hashName: options.hash,
});
}
return options.hash;
}
搞定,亲测后发现,安卓在即使服务器给了我pdiffUrl的情况下,我依然也会去选择全量更新,恩,也就费个3M流量,但是大家都是无线网,所以20S以内,这个热更新肯定就好了,就不需要等待那么久了。
问题
我发现这个index.js文件里没有区分Ios和安卓,所以如果我想让ios走原来的逻辑还需要判断一下,所以后续会测试下好不好用。
用上了bsdiff算法后,切记切记,你的下载地址的ipa包也好,apk包也好,一定一定要和update.reactnative.cn上的包保持完全一致。否则一旦第一次走的是增量更新,那么恭喜你,无限重启。
为什么会出现这样的问题,我的猜测是:
(update.cn上的包是7号,给用户下载地址上的包是8号,8号的程序内容比7号仅仅是多了几个文案修改。这个时候,我推送一个热更新上去,名字叫10号。那么它的计算方式本来是10号减去7号的 = 3,然后拿着这个3去加7 = 10,更新成功。但是你手里的包却是8,他还是拿10-7=3,3+8 却=11!=10.boom爆炸。11!=10,无限热更新。却永远都对不上。所以无限重启)括号内容仅仅是猜测,没有和官方沟通。