React Native拆包及热更新方案 · Solartisan
作者:solart
版权声明:本文图文为博主原创,转载请注明出处。
随着 React Native 的不断发展完善,越来越多的公司选择使用 React Native 替代 iOS/Android 进行部分业务线的开发,也有不少使用 Hybrid 技术的公司转向了 React Native 。要说 React Native 最能吸引开发者的地方那就是其拥有前端的开发速度以及原生的体验。
1、序言
今天要跟大家探讨的是 React Native 的拆包及热更新方案,官方并没有很好的支持这一企业十分看中的热更新能力,因此也催生了第三方的热更新方案,如 CodePush 、 react-native-pushy 。由于公司内部有不同的业务线,所以在采用第三方的热更新方案灵活度不够,在调研的初期,我们参考了携程的提到的 jsbundle 拆分和加载优化方案,但这个方案需要改变 React Native 的打包代码及 Runtime 代码,实施难度上非常大,暂无精力深入研究,但这个方案对加载速度提升也是显而易见的。我们暂时放弃了携程的方案,我们前期需要一套相对简单稳定且可行度高的方案,在经过调研及讨论后定下了这样一套热更方案,今天我们就来聊聊这个方案。
2、流程梳理
由于存在多条业务线开发,又希望业务线之间互相独立,但是全量的 bundle 文件又过于庞大,基于这样的考量,我们决定采用业务代码独立热更的方案。
整体流程其实非常简单,不过内部一些细节规则需要仔细推敲。

3、热更新模块的实现方案
当下选择使用 React Native 的项目大都是基于原有项目的基础上进行接入,所以要达到上线的项目的状态自然要各方面都准备就绪,热更新就作为基建工程之一。以下主要以 Android 端为例进行阐述,iOS 端方案基本一致。
3.1 jsbundle 的拆分
对 React Native 的代码打包编译后会生成一个 bundle 文件,这里要说明一下,jsbundle 的拆分是基于生成的 bundle 文件可以看成两部分构成(如下图):一是 React Native 包含的的基础类库,一是开发的业务代码。

基于 bundle 文件的这一特点,我们就可以将完整的 bundle 文件拆分为两部分:
首先需要做的就是生成 common.bundle ,新建一个 blank.js 文件,在文件中仅引入 react 及 react native :
1 |
import React from 'react'; |
通过打包命令编译成 common.bundle :
1 |
react-native bundle --entry-file blank.js --bundle-output ~/Desktop/common.bundle --platform android --dev false |
其次,打包完整的 jsbundle ,这将会包含所有的基础类库及业务代码。提醒一句保持 import 的公共模块一致:
1 |
import React from 'react'; |
最后根据 diff 算法将两个文件进行 diff 拆分,由此会生成一个 *.diff 的二进制文件,例如 index.diff 。

到这里,大家会得到一个 common.bundle 的文件,一个或多个 *.diff 文件。
关于 diff 算法的使用,记得有几篇文章中推荐 google-diff-match-patch ,虽然 Google 这个开源版本包含多种语言的实现,但由于是基于纯文本的 diff 所以在当下这个场景下并不十分合适,我还是推荐大家使用基于二进制的 diff ,在此也推荐另一种 java 版本的 bsdiff 的实现:jbdiff 。
3.2 bundle 文件的拷贝及合成
在完成拆分以后,我们需要将 common.bundle 及拆分的 *.diff 文件进行 zip 压缩,放入 assets 目录下,为了方便版本管理,我们将其文件名中写入版本号 jsbundle_<版本号>.zip ,例如:jsbundle_1.zip ,每次改 zip 文件包跟随发版时更新,并自动升级版本号。
接下来我们要做的就是将内置于 assets 目录下的 jsbundle_*.zip 拷贝至内部存储,这里不推荐使用外部存储,尽量避免用户删除这些文件。
在拷贝过程中根据历史记录的版本号,进行判断是否需要执行拷贝,拷贝完成后将 common.bundle 及*.diff 文件进行 patch 合并,合并后的文件即为一个完整的 bundle 文件,文件名规定为 *.diff.bundle ,例如:index.diff.bundle ,在加载时根据模块名进行加载即可。
3.3 diff 文件的更新
说到热更新,反而在关于 *.diff 文件的更新本身并没有什么复杂度,简单来说就是下载替换 *.diff 文件,并合成新的完整 bundle 文件,其他需要注意的则是关于 diff 文件版本的控制。
其他主要工作量在于 diff 文件的生成及上传,这部分工作量最好是不依赖于人工,可以考虑编写 shell 脚本自动完成,以下摘录部分 packer.sh 的打包代码供参考。
1 |
if [ $platform == "android" ]; then |
3.4 对于容器 Activity 的改造
由于对于 React Native 的 bundle 文件加载做了更改,我们就不能直接使用 sdk 提供的 ReactActivity 了,对此我们需要对容器 Activity 进行改造。大专栏 React Native拆包及热更新方案 · Solartisanp>
而改造的最终落脚点其实是 ReactInstanceManager 的构建,由于我们需要按业务模块加载,所以最终将其进行了部分改造:
1 |
public class extends ReactNativeHost{
|
将改造后的 Activity 容器也要接入原有项目的路由框架(如果项目本身有的话),至此,整个更新加载就可以串起来了。由于 React Native 本身没有提供 reload 机制,如果需要在更新 bundle 文件后强制刷新页面,需要通过反射处理 ReactInstanceManagerImpl::recreateReactContextInBackgroundFromBundleLoader 达到重新加载刷新页面的效果,比较简单,这里就不再赘述。
4、热更新改造的后遗症
由于采用加载文件系统下的 bundle 文件的形式,在测试过程中发现通过此形式加载的 bundle 文件,图片加载时不能读取到 res 目录下的资源文件,带着这个问题看了相关的 js 源码,发现了一个有意思的地方:
1 |
... |
看到这里就明白了,源码中对资源的加载保持了跟 bundle 文件同源。要解决这个问题有两个方案:1、将 js 源码中的逻辑进行修改,都从 res 中读取资源;2、将 React Native 使用到的资源打包到本地,跟随 jsbundle_*.zip 发布。我个人比较倾向于第二个方案,我主要考虑两点:一是后续 React Native 版本升级的成本,一是可以对于 React Native 的资源单独管理,同时也意外的获得了一个 React Native 资源热更的能力。
整个更新方案到这里基本阐述完毕,方案简单且可行度高,唯一的遗憾是在加载速度上并没有什么提升。我个人感觉 React Native 在 Android 端的加载速度还是个硬伤,机型众多,性能差异极大,在 iOS 端的表现就好上很多 。
最后,吐槽下 React Native 的一个坑,目前最新的 0.41.0 版的 Android 端通过<Image /> 的 loadingIndicatorSource 属性来指定占位图依然无效,15 年的一个 issues #5017 到现在没有被修复,实在匪夷所思,感觉我是用了假的 RN !!
React Native拆包及热更新方案 · Solartisan的更多相关文章
- 在React Native中集成热更新
最近,在项目DYTT集成了热更新,简单来说,就是不用重新下载安装包即可达到更新应用的目的,也不算教程吧,这里记录一下. 1.热更新方案 目前网上大概有两个比较广泛的方式,分别是 react-nativ ...
- 移动端热更新方案(iOS+Android)
PPT资源包含iOS+Android 各种方案分析:https://github.com/qiyer/Share/blob/master/%E7%83%AD%E6%9B%B4%E6%96%B0%E5% ...
- 腾讯开源手游热更新方案,Unity3D下的Lua编程
原文:http://www.sohu.com/a/123334175_355140 作者|车雄生 编辑|木环 腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源 ...
- Unity代码热更新方案 JSBinding + SharpKit 首页
目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...
- 【腾讯Bugly干货分享】手游热更新方案xLua开源:Unity3D下Lua编程解决方案
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2bY7A6ihK9IMcA0bOFyB-Q 导语 xL ...
- Unity3D 热更新方案(集合各位专家的汇总)
http://blog.csdn.net/guofeng526/article/details/52662994 热更新”这个词,在Unity3D的应用下,是有些语义错误的,但是作为大家都熟知的一项技 ...
- Unity实现c#热更新方案探究(三)
转载请标明出处:http://www.cnblogs.com/zblade/ 前面两篇文章从头到尾讲解了C#热更新的一些方案,从程序域来加载和卸载DLL,到使用ILRuntime来实现安卓和IOS平台 ...
- Unity3D 热更新方案总结
如何评价腾讯在Unity下的xLua(开源)热更方案? Unity 游戏用XLua的HotFix实现热更原理揭秘 腾讯开源手游热更新方案,Unity3D下的Lua编程 [Unity]基于IL代码注入的 ...
- iOS 热更新方案 - lance的专栏 - 博客频道 - CSDN.NET
iOS 热更新方案 - lance的专栏 - 博客频道 - CSDN.NET Weex
随机推荐
- Python3+Pycharm+PyQt5环境搭建
操作系统:Windows 10 Python版本:3.7及以上版本均可 PyCharm:PyCharm 2019.3 1.安装 PyQt5 及其拓展工具. pip install pyqt5 pip ...
- goweb-goweb基础
goweb DNS工作原理 在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析. 如果hosts里没 ...
- 17.3.15---关于GPIO控制流水灯的信息
添加一个网址: http://rmingwang.com/gpio-control-flow-lamp-code-archive.html 还有一个 http://www.openedv.com/po ...
- RDD(十)——案例实操
需求: 数据结构:时间戳,省份,城市,用户,广告,中间字段使用空格分割. 样本如下: 1516609143867 6 7 64 16 1516609143869 9 4 75 18 151660914 ...
- 基础服务系列-Jupyter Install TensorFlow
TensorFlow is a deep learning framework that provides an easy interface to a variety of functionalit ...
- Hibernate一级缓存Session和对象的状态
建议看原文:https://blog.csdn.net/qq_42402854/article/details/81461496 一.session简介 首先,SessionFactor ...
- Python2 和 Python3的区别 更新中
py2和py3的区别 1.默认解释器编码 py2: ascii py3: utf-8 2.输入 输出 输入 py2: name = raw_input('请输入你的姓名:') py3: name = ...
- 吴裕雄--天生自然 JAVA开发学习:多线程编程
class RunnableDemo implements Runnable { private Thread t; private String threadName; RunnableDemo( ...
- winform显示word和ppt文档
最近所做的项目中需要在Winform窗体中显示Office文档.刚开始就使用webBrowser控件实现的,但是后来发现这个控件在显示Office文档的时候有个限制:只支持Office2003之前的版 ...
- appium自动化的工作原理(1)
用appium开发移动端自动化测试脚本这么长时间,还没有认证的了解下它的原理是什么,到底是如何实现的呢? 1.先看一个Appium加载的过程图解(来自:了解appium自动化的工作原理--https: ...