Upgrade

每个app都是在不断升级中,我们所使用的常见的app,基本上都是每隔一段时间都会有升级提示,所以这也显示出app版本更新的常用性。关于RN的热更新,网上有很多现成方案,一般都依赖第三方服务。

RN热更新#

热更新原理#

  • react-native 的程序实际上是原生的模块+JS和图片资源模块,热更新,就是更新其中的js和图片资源。

  • 安卓程序把它名字命名为zip解压后可以清楚的看到其中的bundle文件和资源文件

    热更新的方法#

    热更新又分为全量更新和增量更新。

  • 全量更新是直接去服务器抓取你上传的ppk文件,下载下来,直接覆盖本地的ppk文件。

  • 增量更新是使用了bsdiff算法,用来比对两者bundle之间的区别,然后只修改不一样的地方。

使用的是第三方更新组件 react-native-update


启动程序的时候,会发一个请求给服务器,询问我需不需要更新

URL: http://update.reactnative.cn/api/checkUpdate/${key}

抓包也好,看源码也好,结论就是使用的是这个请求带上自己热更新json的key值,用来匹配你的app

{
"upToDate": true,
"ok": 1
}

这个是服务器返回给我的值,如果是已经是最新的版本了,就会返回upToDate给我。

{
"expired": true,
"downloadUrl":'xxx',
"ok": 1
}

如果是需要硬版本更新了,就会返回一个expired的给我,顺便给我一个downloadUrl(随便写的,具体可能不是这个名字,懒的再去删版本看了)的参数,当然这个参数是我在他家官网配置的,就是我新版本的下载地址。

这个时候,如果是需要热更新了,根据当前版本react-native-update@4.xxx的大量数据试验情况来看,返回格式无非就两种,虽然源码里有第三种

{
"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已经跑起来了,后台程序数据涨起来了,但是流量没动,因为走的是内部计算.

关于服务器是否返回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;
	}

搞定