基于React Native的移动平台研发实践分享

时间:2021-11-29 20:22:57

转载:http://blog.csdn.net/haozhenming/article/details/72772787

本文目录:

一、React Native 已经成为了移动前端技术的趋势

二、基于React Native 进行移动平台研发过程中的一些思考

三、基于React Native 进行移动平台研发过程中的一些实践

四、小结

一、React Native 已经成为了

移动前端技术的趋势

从2014年年底,Facebook计划开源React Native 的时候,我就已经开始关注TA了,关注的主要原因是,我们在2012年的时候,将我们的移动平台前端开发技术确定为“DSL->JavaScript->Native Mobile”这个技术流派。要知道在那个时代,绝大多数的友商要么选择Hybrid,要么选择HTML5作为移动平台的跨平台前端解决方案。

然而,这两种方案最终的UI渲染,本质上都需要依赖Webkit,通俗点说就是UI最终是通过浏览器内核渲染。我们当时在技术选型的时候实在无法容忍Webkit在Andriod上的体验,而选择了驱动原生(注:这个名字是我起的,也是为了区别于传统的Hybrid技术)的方式。

当时的这个技术抉择,在当时是冒着巨大的风险的,现在看来,我们是非常幸运的。

后来Facebook 推出React Native 后,阿里系也推出了自己的Weex,甚至Gartner针对这类技术在2016年的报告(IT Market Clock for Mobile App Development, 2016 )中首次出现并并为这个技术流派起了一个名字——Javascript Frameworks for Native Mobile。

 

基于React Native的移动平台研发实践分享

Garnter将这个技术流派当如了“Advantag”中,可见Gartner对这个技术流派的认可。

Javascript Frameworks for Native Mobile这类技术的几个特点:

  • 开发期基本采用类Web语言,比如React的语法。

  • 运行期并不是采用Webkit做渲染,而是采用Native的渲染方式。

  • 与Native 进行交互的通道是采用Javascript的方式。

当然,因其技术的先进性让各大互联网公司纷纷进行实践上的尝试,取得了不错的效果,包括天猫、腾讯QQ、手机百度、美团点评、携程等等。React Native 也建立了很好的生态,大家对案例如果有兴趣可以关注一下https://facebook.github.io/react-native/showcase.html

 

二、基于React Native 进行移动平台

研发过程中的一些思考

尽管React Native 在移动前端存在着无可比拟的优势,但每一家在工程化的过程中还是存在各自不同的思考。而作为移动平台,不是简单的解决单一的一个App的问题。

移动平台是支撑企业全面移动信息化的平台,需要解决企业面向不同场景下的各种诉求。针对移动App的使用者的场景不同,存在面向人和面向组织两种不尽相对的要求:

基于React Native的移动平台研发实践分享

面向人:每个人对应的App功能是基本相同的。人与人是平等的,就如今天在线的各位和我一样,在支付宝里看到的功能是相同的。这种情况多出现在面向最终消费者的时候。

面向组织:是指功能因其所属的组织和职级决定了其所见和所能用的功能。当事人所处的组织机构发生了变化,功能也随之产生变化。

针对面向组织,需要举个例子来说明一下:假如我本人之前是一名普通的manager,其实对于产品线的经营报告并无权阅读(图一);当我被Promote 为产品线总经理的时候,我的App里就应该有“智能报表”的微应用(图二);当我调岗到别的团队(比如从事行政工作),我就不应该再具有“智能报表”的相关功能(图三),如下图所示:

基于React Native的移动平台研发实践分享

随着岗位和职级的变化,功能从图一到图二再到图三,我还是我,而我App内的功能却发生了变化,这在企业中是非常常见的诉求。

实现上述的功能,从技术方案角度看,有多种方式,但是怎么更合理呢?我们可以思考一下。

首先,“智能报表”功能是否可以将UI已经打入App中,通过权限控制对应的前端“智能报表”是否显示?回答是不可以。主要原因有三:

  • 类似这种功能在企业中非常多,如果要将UI全都打入到App中,这需要所有功能的全集,没有三四百M下不来。而用户实际上只有权限使用几分之一甚至是十分之一的功能,却要每次为此多更新两三百M,这是不合理的。

  • 如果智能报表这个功能在用户安装ipa或者apk的时候,尚未开发完成,而是后续才迭代上线的,那么这个用户就无法及时使用到这个功能。

  • 如果失去了相关的功能权限,需要的是相关的功能清除,甚至包括其相关的数据,而不是简单的隐藏,这既不安全又不合理。

这就意味着,移动平台必须能够动态的方式更新应用内功能,而且必须能够结合权限提供按需的热更新能力。

其次,在企业中不得不面对的是多供应商的问题,智能报表功能跟其他功能(比如:审批)是一个开发团队开发的吗?

显然,在企业中完全有可能是不同的供应商进行的开发。不同供应商之间,不

可能做到代码级的共享的,拿到所有移动项目的代码再进行打包,这是一件非常难以推动的事情。

移动平台必须保证对于多团队、跨地域的方式也能支持并行研发。这就意味着必须提供开发期的隔离。

移动平台需要支撑上述的业务场景,显然直接使用React Native 是难以满足要求的,这就引发了我们对于React Native实践的一些思考。

思考一:React Native 的学习成本和可替换性

作为移动平台,不得不考虑的是学习成本,在企业的供应商中是否能够对React Native的技术储备达到相关的要求,如何能够屏蔽对于技术实现的细节。

众所周知,React Native 发布版本非常的频繁,一个周之前已经发到0.44,对于大规模使用时,如何屏蔽版本的频繁升级导致的业务代码的重构,方便进行版本的可替换性。

如果能够将React Native实现换成其他实现(比如Weex),而上层业务代码能否不需要调整,真正做到实现的可替换性。

基于这一点的思考,移动平台采用了基于传统Web语法的DSL,作为开发期语言,降低了RN的学习成本;同时DSL层可以隔离业务代码与平台实现相关性,为后续RN版本更新等提供了良好的隔离,大致的示意图如下:

 

基于React Native的移动平台研发实践分享

这里需要说明的一点是,我们并没有真正考虑基于Weex作为移动平台的一种实现,而是从技术架构上成为一种可能性。

思考二:React Native 的单bundle VS 多bundle

在谈论React Native的单Bundle与多Bundle的问题之前,首先,我们先回头看一下React Native 默认的Bundle 机制。

在基于RN编写App时,无论开发期创建多少个文件,RN都会将这些文件一并打到一个bundle里去,简单说默认的RN就是一种单bundle的方式,其打包bundle的大概过程如下:

 

基于React Native的移动平台研发实践分享

因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为例(后续出现的代码均为示例代码片段):

基于React Native的移动平台研发实践分享

DSL语言会在开发期编译成JSX,然后再编译成可被React Native 运行的javascript(涉及到拆分Bundle和编译,这里暂不展开)。

DSL编译成JSX,主要的工作原理大致如下:

  • HTML 标签的处理,主要是与RN的render进行关联

  • CSS 的处理,主要是与RN的StyleSheet进行映射

  • Javascript的处理,主要是嵌入到JSX中

基于React Native的移动平台研发实践分享

上面的代码示例左侧为基于DSL语言编写的代码,右侧是生成JSX后的代码。

实际上,在工程化过程中,并不是像上面的示例代码那么容易做好,无论标签的定义,还是从DSL转换成JSX都是一个巨大的工程,且会遇到很多的问题。

实践二:拆分Bundle

在拆分Bundle上,我们遵守两个原则:

1、将系统库作为一个bundle文件,独立存在。

2、将每个的Module作为一个独立bundle文件

这种拆分原则将bundle拆分成小粒度的针对Module级别的bundle,这带来的好处是,可以方便的跟DSL中HTML文件进行一一映射,其加载单元的粒度可以理解为Page级别,而非整个App。

我们以require 为例,下图为默认的加载方式,如果没有对应的Module Factory,就会以异常结束,如下图:

 

基于React Native的移动平台研发实践分享

扩展后,当判断没有对应的Module Factory的情况下,并不是以异常退出,而是增加了加载对应的Module级别的bundle,如下图所示;基于React Native的移动平台研发实践分享

当然,这就必须需要移动平台自行实现RTC_PM_JSCExcutor用于加载Module级别的Bundle。这一部分代码需要采用原生的Object-C或者Andriod Java实现,下面以iOS的示例代码

 

基于React Native的移动平台研发实践分享

实践三:引入微应用

在将每个Module打成一个Bundle后,会让项目内资源的关系不易管理,这时我们引入了微应用的概念,用于完善应用内逻辑关系。

 

基于React Native的移动平台研发实践分享

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等文件的资源变化即可。如下图:

 

基于React Native的移动平台研发实践分享

而这里的编译引擎基本上做的事情是:

1、DSL->JSX

2、JSX->js

其中后者主要的工作如下所示:

 

基于React Native的移动平台研发实践分享

而为了能够更好的调试,需要对相关两种更新机制:

  • 批量更新

a)包括初次批量更新部署,下载所有文件

b)使用过程中检查文件更新部署,判断需要更新的文件列表

  • 单页更新

单页更新是确保其可以当前页保存,当前页刷新调试的主要机制

 

基于React Native的移动平台研发实践分享

通过上述的方式,结合移动平台的IDE,可以提供

1、同时支持多手机终端的多屏调试(可以同时iOS和Andriod)

2、提供了当前屏动态刷新动态调试

实践五:按需热更

当上述的实践完成后,按需更新就成了一个相对较容易做到的事情。所以移动平台提供了两级打包编译机制,在无需调整代码的情况下,可以选择以微应用的方式出现其他的App内,还是以独立的ipa/apk的方式存在以移动设备中。其基本原理如下图所示:

基于React Native的移动平台研发实践分享
 

四、小结

基于React Native进行移动平台研发是一个系统性的工程,上述的工作仅仅是其中的一小部分,期间的坑还有很多,这篇文章也仅是从大粒度的方面进行了分享。

基于React Native的移动平台研发实践分享的更多相关文章

  1. 基于React Native的58 APP开发实践

    React Native在iOS界早就炒的火热了,随着2015年底Android端推出后,一套代码能运行于双平台上,真正拥有了Hybrid框架的所有优势.再加上Native的优秀性能,让越来越多的公司 ...

  2. 腾讯优测优分享 | 探索react native首屏渲染最佳实践

    腾讯优测是专业的移动云测试平台,旗下的优分享不定时提供大量移动研发及测试相关的干货~ 此文主要与以下内容相关,希望对大家有帮助. react native给了我们使用javascript开发原生app ...

  3. 探索react native首屏渲染最佳实践

    文 / 腾讯 龚麒 0.前言 react native给了我们使用javascript开发原生app的能力,在使用react native完成兴趣部落安卓端发现tab改造后,我们开始对由react n ...

  4. 基于React Native的Material Design风格的组件库 MRN

    基于React Native的Material Design风格的组件库.(为了平台统一体验,目前只打算支持安卓) 官方网站 http://mrn.js.org/ Github https://git ...

  5. DCOS实践分享(3):基于Mesos 和 Docker企业级移动应用实践分享

    2016年1月24日 8:00—19:00 北京万豪酒店(东城区建国门南大街7号) @Container大会是由国内容器社区DockOne组织的专为一线开发者和运维工程师设计的*容器技术会议,会议强 ...

  6. 基于React Native的跨三端应用架构实践

    作者|陈子涵 编辑|覃云 “一次编写, 到处运行”(Write once, run anywhere ) 是很多前端团队孜孜以求的目标.实现这个目标,不但能以最快的速度,将应用推广到各个渠道,而且还能 ...

  7. 【react native】rn踩坑实践——从输入框“们”开始

    因为团队技术栈变更为react native,所以开始写起了rn的代码,虽然rn与react份数同源,但是由于有很多native有关的交互和变动,实际使用还是碰到蛮多问题的,于是便有了这个系列,本来第 ...

  8. React Native(十五)——RN中的分享功能

    终于,终于,可以总结自己使用RN时的分享功能了-- 为什么呢?且听我慢慢道来吧: 从刚开始接触React Native(2017年9月中旬)就着手于分享功能,直到自己参与公司的rn项目开发中,再到现在 ...

  9. React Native中集成友盟社会化分享-----童叟无欺

    1.下载所需的jar,下载地址https://developer.umeng.com/sdk/reactnative?spm=a211g2.211692.0.0.28967d238GW6mC 2.将以 ...

随机推荐

  1. java获取类路径

    String file = MessageTask3.class.getResource("").getFile(); File: public static final Stri ...

  2. Makefile条件推断 ——————————【Badboy】

    使用条件推断,能够让make依据执行时的不同情况选择不同的执行分支. 条件表达式能够是比較变量的值,或是比較变量和常量的值. 一.演示样例 以下的样例,推断$(CC)变量是否"gcc&quo ...

  3. 深入tornado中的http1connection

    前言 tornado中http1connection文件的作用极其重要,他实现了http1.x协议. 本模块基于gen模块和iostream模块实现异步的处理请求或者响应. 阅读本文需要一些基础的ht ...

  4. 【原创】Struts2.5.12版本中使用通配符*

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. <package name="hellodemo" extends="struts-default&quo ...

  5. &lbrack;HAOI2008&rsqb;木棍分割

    题目大意 网址:https://daniu.luogu.org/problemnew/show/P2511 题目大意: 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连 ...

  6. Matlab信号处理基础

    一. 简介 离散傅立叶.离散余弦和离散小波变换是图像.音频信号常用基础操作,时域信号转换到不同变换域以后,会导致不同程度的能量集中,信息隐藏利用这个原理在变换域选择适当位置系数进行修改,嵌入信息,并确 ...

  7. js 计算快速统计中用到的日期

    前言 最近在做统计报表模块,其中查询条件用到了快速查询,主要为了方便客户统计查询常用的几个日期纬度,比如本周.上周.本月.上月.昨日. 使用js计算,主要用到了js Date. getDate().g ...

  8. python同时遍历两个list

    两个list, 有对应关系,希望同时完成遍历 用迭代器迭代的方法也不是不可以,python提供了更直观的方法: 可以使用zip把两个list打包 , 类似: list1 = [1,2,3,4] lis ...

  9. html 5中的新特性之强化表单元素及属性

    之前我们判断用户提交的是否是Email 的时候,往往使用js 进行判断,但在html5中可以有新的方式进行判断而且更简单 <!DOCTYPE html> <html lang=&qu ...

  10. Jstl标签&lt&semi;c&colon;if&gt&semi;的用法

    <c:if> 标签必须要有test属性,当test中的表达式结果为true时,则会执行本体内容:如果为false,则不会执行.例 如:${requestScope.username = = ...