因React Native 默认采用的是单Bundle的模式,所以,其更新机制也就仅仅能够以替换这个Bundle的方式进行,虽然有一些通过diff的方式提供增量更新的方式,但这种方案仍然无法满足上面例子中的“智能报表”的按需获取的能力。
另外,在进行编译打包的时候,需要获取所有项目的源代码,这对于多供应商的情况下也不适用。
所以需要解决的两个问题是:
1、在打包Bundle时,必须提供以多Bundle的方式进行。
2、在开发期,必须解决多微应用每个能够独立以Project的方式存在。
思考三:React Native 的调试的首屏进入VS 当前屏刷新
对于开发工程师,很重要的工作就是调试,以RN默认的单Bundle模式,势必会带来另外一个挑战,就是当资源发生任何变化时,必须重复上述的打包Bundle的过程并进行加载,看到的UI界面永远是第一屏。
实际上,我们期望的绝大多数场景是看到当前修改的资源所在的屏的UI效果。从这个维度看,我们必须能够将Bundle控制在一个资源的粒度,并确保当前bundle的动态热更。
另外,虽然React Native 默认不承诺跨平台,但跨平台(即一套代码同时支持iOS、Andriod)是移动平台的必备特性了。如何能够支持多屏同时调试,也将是一个必须考虑的问题。
思考四:React Native 的热更新VS 按需更新
说到热更新,这里不得不提的是几个月前,一堆的App被苹果拒掉的事情,这个事情曾一度让React Native 等Javascript Frameworks for Native Mobile 技术流派背黑锅。
其实这件本质上还是因为某些热更方案调用了私有的API而引起的,后来导致的局面时一堆三方的SDK都受到牵连,最终导致了使用这些SDK的App被拒。插一句,我个人觉着第三方的SDK在没有让使用它们的App知晓的情况下就进行热更新,就是耍流氓,谁又能保证更新后的SDK不做点什么呢。
回到热更本身,我认为,基于React Native 进行热更应该是一个必须的特性,而实际上我们需要提高要求,提供按需更新的能力。
三、基于React Native 进行移动平台
研发过程中的一些实践
基于上面的一些思考,我们基于React Native进行了一些实践,这里挑出几点给各位做个简单分享。
实践一:引入DSL层
首先,我们引入了DSL层,这里的语法采用了传统web工程师熟知的html、CSS、Javascript,而使用移动平台的工程师无须对React进行过多的深入。在HTML的标签定义中,从语义上尽量能够对开发人员亲切,从习惯上尽量保留原有开发人员的一些习惯,比如对state的封装以getter、setter的方式提供能力,而这些标签需要一一以React Component的方式进行了实现。我们以Label为例(后续出现的代码均为示例代码片段):
DSL语言会在开发期编译成JSX,然后再编译成可被React Native 运行的javascript(涉及到拆分Bundle和编译,这里暂不展开)。
DSL编译成JSX,主要的工作原理大致如下:
HTML 标签的处理,主要是与RN的render进行关联
CSS 的处理,主要是与RN的StyleSheet进行映射
Javascript的处理,主要是嵌入到JSX中
上面的代码示例左侧为基于DSL语言编写的代码,右侧是生成JSX后的代码。
实际上,在工程化过程中,并不是像上面的示例代码那么容易做好,无论标签的定义,还是从DSL转换成JSX都是一个巨大的工程,且会遇到很多的问题。
实践二:拆分Bundle
在拆分Bundle上,我们遵守两个原则:
1、将系统库作为一个bundle文件,独立存在。
2、将每个的Module作为一个独立bundle文件
这种拆分原则将bundle拆分成小粒度的针对Module级别的bundle,这带来的好处是,可以方便的跟DSL中HTML文件进行一一映射,其加载单元的粒度可以理解为Page级别,而非整个App。
我们以require 为例,下图为默认的加载方式,如果没有对应的Module Factory,就会以异常结束,如下图:
扩展后,当判断没有对应的Module Factory的情况下,并不是以异常退出,而是增加了加载对应的Module级别的bundle,如下图所示;
当然,这就必须需要移动平台自行实现RTC_PM_JSCExcutor用于加载Module级别的Bundle。这一部分代码需要采用原生的Object-C或者Andriod Java实现,下面以iOS的示例代码
实践三:引入微应用
在将每个Module打成一个Bundle后,会让项目内资源的关系不易管理,这时我们引入了微应用的概念,用于完善应用内逻辑关系。
1、将原有的一个App对应一个Bundle的模式,改成一个App对应多个MicroApp,一个MicroApp对应多个Bundle模式。
2、将原有的一个Bundle对应多个Module的模式,裁剪成一个Bundle对应一个Module的模式
实践四:多屏调试
多屏调试与当前屏刷新,在移动平台IDE端的产品的定义中还是占有很重要的地位,因其直接影响了开发期的效率。
针对React Native 默认的编译核心框架,我们简单的可以总结为四件事情:
node-haste:主要是监听Module变化 ,把变化的Module从Module缓存中移除。
ModuleCache:Module编译缓存,把编译好的Module缓存起来,Module没有发生变化的情况下,直接使用缓存组装成bundle
Resolver:实现全局系统级库,语法级兼容实现,包括:ES5,ES6实现 兼容实现的引入 。实现Module factory的包装
JSTransformer:调用Babel编译JSX文件到JS。
其中1和2有很大原因是因为单bundle导致,当每个HTML文件对应一个Module,每个Module 对应一个bundle后,移动平台需要的就是监听HTML等文件的资源变化即可。如下图:
而这里的编译引擎基本上做的事情是:
1、DSL->JSX
2、JSX->js
其中后者主要的工作如下所示:
而为了能够更好的调试,需要对相关两种更新机制:
批量更新
a)包括初次批量更新部署,下载所有文件
b)使用过程中检查文件更新部署,判断需要更新的文件列表
单页更新
单页更新是确保其可以当前页保存,当前页刷新调试的主要机制
通过上述的方式,结合移动平台的IDE,可以提供
1、同时支持多手机终端的多屏调试(可以同时iOS和Andriod)
2、提供了当前屏动态刷新动态调试
实践五:按需热更
当上述的实践完成后,按需更新就成了一个相对较容易做到的事情。所以移动平台提供了两级打包编译机制,在无需调整代码的情况下,可以选择以微应用的方式出现其他的App内,还是以独立的ipa/apk的方式存在以移动设备中。其基本原理如下图所示:
四、小结
基于React Native进行移动平台研发是一个系统性的工程,上述的工作仅仅是其中的一小部分,期间的坑还有很多,这篇文章也仅是从大粒度的方面进行了分享。
来源: http://blog.csdn.net/haozhenming/article/details/72772787