写点什么

React Native 原生混合路由解决方案

  • 2021-05-31
  • 本文字数:3103 字

    阅读完需:约 10 分钟

React Native 原生混合路由解决方案

在 RN 出来前许多公司都已经有一套完整的 App,可能业务复杂、依赖繁多,在这种情况下,将原有的 App 推翻重写明显是不切实际的,成本和风险都较高。所以如何进行混合性开发则至关重要。


目前 RN 官方建议的路由框架为 react-navigation,这个框架大部分逻辑是 javascript 编写的,RN 页面的栈管理由 JS 端控制,所以当原生和 RN 页面混合开发时,由于原生栈和 RN 栈不一致,导致栈管理较混乱。出现 RN - 原生 - 原生 - RN 跳转场景时,若为单一的 RN 容器管理,则需要在返回时判断上一个页面为 RN 还是原生,嵌入基类修改;若为多 RN 容器管理,则也需要在跳转时区分是跳转原生还是 RN。


另外网上还比较广泛使用是 react-native-navigation 框架,它使用 iOS 和 Android 原生的基础 Api。但是混合开发的问题还是和 react-navigation 一致,JS 自己管理栈和原生栈不统一,导致栈管理复杂,跳转需要做额外的处理。所以通过对市面上的一些路由分析,我们通过对 react-native-navigation 框架的改造,抛弃了 JS 端的栈管理,将一个 RN 页面对应一个容器,使得 RN 的栈管理融入原生的栈管理中。


WYNavigation

主要概念


我们采用单引擎多容器的模式。前期我们已经对现有的 RN 代码进行了拆包,分为一个 common 包和 n 个 business 包。并且原生工程中每个页面都是以 RouteUrl(类似浏览器地址)的方式进行跳转的。这两点为我们的方案提供了技术支持。共用一个 common 包使得我们的代码共享一个 RN 引擎,RouteUrl 的模式也使得我们在跳转页面时不需要去关心是跳转原生还是 RN 页面。下面是打开一个 RN 页面的流程:和 react-native-navigation 一样,我们会将所有的 RN 页面在 Navigation 进行注册,Test 为这个 RN 页面的对外名称。


Navigation.registerComponent("Test", () => TestScreen)
复制代码


在原生主工程启动时会先预加载 common 包,当需要打开一个 RN 页面时,原生会先打开一个 RN 容器,根据传递过来的 PageName 找到对应的 business 包加载,再将 PageName 传到 RN 端,RN 端根据 PageName 找到对应的 RN 页面显示,容器根据找到的 RN 页面中的静态变量初始化原生导航栏,这样因为该 RN 容器等于一个原生页面,这个容器中只有一个 RN 页面,所以一个 RN 页面等于一个原生容器,从而将该 RN 页面嵌入到了原生导航栈中。这样就实现了 RN 和原生导航栈的统一。



组件、页面、容器的理解


这里我们要说 3 个概念:组件 (Component):RN 上具有独立功能的单位,一个页面由多个组件组成。页面 (Screen):UI 意义上的页面,包括导航栏及内容显示。容器 (RNContainer):原生用来容纳 RN 的容器,用于显示 RN 页面。我们的方案是多个组件 = 一个页面 = 一个容器 = 一个原生页面,所有 RN 页面上的 push 和 pop 实际上最后都会经过容器的原生跳转,这样处理就相当于 RN 页面进行跳转和返回时和原生并没有什么区别。



路由的跳转


结合我们现有的 App 路由模式,我们统一 iOS 和 Android 两端容器的协议,将 RN 页面名称通过参数的形式进行传递。


原生跳转到 RN


从原生页面跳转到 RN 页面时,需要指定一个入参 pageName,即要跳转的 RN 页面的名称。如果需要传参,定义一个字典,键为 param,值是传递的参数。如下,MyPost 是一个 RN 页面的名字。


// 原生跳转 RNNSDictionary *params = @{@"pageName": @"MyPost", @"param": param};[WYMediator routeURL:WYURL(@"xxx/rncontainer") withParams:par];
复制代码


// 原生跳转ExtParams param = new ExtParams();param.putStringExtra("PageName", "MyPost");param.putStringExtra("PageParam", pageParams);Router.startRoute(activity, "xxx/rncontainer", param);
复制代码


RN 跳转到原生


从 RN 页面跳转到原生页面,也遵循我们的路由协议。这个过程是原生实现的,它会调用原生的路由组件,从 RN 容器跳转到指定的原生页面。如下,name 指的是原生页面对应的协议,passProps 则是需要跳转到的原生页面需要的参数,没有则可不写。最后一个参数是回调函数,当执行 push 方法时,路由会根据传入的 componentId 将回调函数保存在 JS 端,原生页面关闭后回到当前 RN 页面时,路由会根据当前页面的 component 取出回调函数并执行。


Navigation.push(this.props.componentId, {    name:"xxxx",    passProps:{patientId:'11111', patientName:'张三'}}, (componentId, params) => {    // 返回当前页面的回调函数});
复制代码


RN 跳转到 RN


RN 之间的跳转和 RN 跳转到原生相同,通过 push 的方法传递 name、passProps 和 callback 回调,只不过这里的 name 不再是原生的协议,而是以下注册的名称。


Navigation.registerComponent("Test", () => TestScreen);
复制代码


RN 页面返回


需要关闭当前 RN 页很简单,只要调用 pop 方法就行。


Navigation.pop(this.props.componentId, passProps:{})
复制代码


passProps 指的是需要传递回上一个页面的参数,用于之前 push 中的 callback 方法的回调,没有则可不写。


容器生命周期


RN 的组件 Component 有自己的生命周期:


  • constructor() // 构造方法

  • componentWillMount() // 即将加载

  • componentDidMount() // 加载完成

  • componentWillUnmount() // 组件已被卸载


但是有时候我们光这些并不能满足我们的业务需求,对于一个 RN 页面对用一个容器来说,容器的生命周期也至关重要,我们需要在容器的隐藏显示过程中做点其他事,所以我们在新的路由框架中加入了容器的生命周期:


  • containerWillAppear() // 容器即将显示

  • containerDidAppear() // 容器正在显示

  • containerWillDisappear() // 容器即将消失

  • containerDidDisappear() // 容器正在隐藏


容器的生命周期和组件的生命周期没有必要先后顺序,大多数情况下是在当容器再次显示时需要做一些数据更新时使用,所以可能会调用多次。


导航栏配置


目前导航栏的配置是同 react-native-navigation 框架一样,采用 Tree 的样式将导航参数传入,原生对其进行设置。基本的使用方式如下:


class MyScreen extends Component {  static options(passProps) {    return {      topBar: {        title: {       text: '我的页面'      },        leftButtons: [          {            id: 'buttonOne',            icon: require('icon.png')          }        ],        rightButtons: [],      }    };  }}
复制代码


RN 页面加载的时候,会根据注册的 PageName 获取到当前页面的 Component,上面的例子就是指 MyScreen,从而获取到对应的静态变量 options,再将它传递到当前的 RN 容器中,RN 容器会根据里面的配置生成导航栏进行显示,这样使用原生的导航栏可以保证页面和原生高度重合,而且也不用为了修改原生导航栏而新增桥接类,方便高效。


总结及问题


目前 WYNavigation 已经在微医生项目中投入使用,使用过程中未发现明显 bug,这一方案以一个简单的方式很好的解决了复杂混合场景中导航栈混乱的问题。但是由于目前相关业务涉及到的页面形式单一,所以对于其他 tab、modal 等涉及到多个 RN 页面平级的情况未做过多的深入,但是在未来我们希望能尽快的补充这方面的缺失,把它作为一个通用的解决方案,用于更多的 RN 和原生混合开发的项目中,希望感兴趣的小伙伴和我们一起交流分享。



头图:Unsplash

作者:黄丽丽

原文:https://mp.weixin.qq.com/s/W75sT2px7P9rHJUrmTwY4g

原文:React Native 原生混合路由解决方案

来源:微医大前端技术 - 微信公众号 [ID:wed_fed]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021-05-31 14:003298

评论

发布
暂无评论
发现更多内容

字节二面:HashMap线程不安全体现在哪里?

Java你猿哥

Java 线程 ssm 架构师 HashMap底层原理

统一、飞鹤等快消龙头企业,如何抓住未来10年数智化的机遇?

用友BIP

用友iuap 用友技术大会 快消行业

浅谈测试用例设计 | 京东云技术团队

京东科技开发者

测试 测试用例 测试用例设计 企业号 4 月 PK 榜

校企共建|阿里云与西安电子科技大学人才培养交流会顺利举行

云布道师

校企合作

电信及互联网行业数据安全内控审计建设实践 | 盾见

极盾科技

数据安全

权威学者、企业CFO荟聚上海国家会计学院,共探「智能会计 价值财务」

用友BIP

智能会计 价值财务 用友智能财务 业财融合

企业如何两步实现数据资产化?

星环科技

数据资产化

如何在微服务下保证事务的一致性 | 京东云技术团队

京东科技开发者

架构 微服务 事务 一致性 企业号 4 月 PK 榜

分布式存储技术(上):HDFS 与 Ceph的架构原理、特性、优缺点解析

星环科技

hdfs 分布式存储 Ceph

基于公共信箱的全量消息实现

百度Geek说

大数据 即时通讯 企业号 4 月 PK 榜 公共信箱

度量分析开源社区健康度,助力企业开源生态健康发展——华为开源管理中心王晔晖

开源雨林

开源治理 OSPO OSS Compass CHAOSS

大语言模型的本质:会思考的狗、聪明的马和随机鹦鹉

FN0

AIGC 大语言模型

这一秒,困扰了程序员 50 年!

Java你猿哥

Java 程序员 ssm 计算机

自动化回归测试平台 AREX 0.2.8 版本正式发布!

AREX 中文社区

自动化测试 接口测试 回归测试

数栈V6.0全新产品矩阵发布,数据底座 EasyMR 焕新升级

袋鼠云数栈

大数据 基础软件 数字化转型

请查收!一份2023年程序员不得不看的自救提升指南(彩色终极版)

Java你猿哥

Java 面试 JVM 面经

硬核!阿里P8耗时6月打造的架构师速成手册,颠覆你对架构师的认知

Java你猿哥

架构 分布式 ssm 软件架构 架构师

如何创造数据资产价值?如何对内赋能业务运营,对外创造市场价值?

星环科技

数据资产 数据要素流通

分布式存储技术(下):宽表存储与全文搜索引擎的架构原理、特性、优缺点解析

星环科技

分布式 全文搜索

阿里十年资深码农共享SpringCloud微服务架构实战文档

Java你猿哥

微服务架构 Spring Cloud ssm 架构设计 架构师

企业数据平台建设的基石:构建统一的数据存算能力

星环科技

存算能力

SysCare:为您的操作系统保驾护航

openEuler

Linux 操作系统 openEuler 内核 热补丁

关于聚合根,领域事件的那点事---深入浅出理解DDD | 京东云技术团队

京东科技开发者

DDD 企业号 4 月 PK 榜 聚合根 领域事件

MySQL8.0.32的安装与配置

Java你猿哥

Java MySQL ssm Java工程师

分布式技术剖析

星环科技

分布式

竞争焦点转向数智底座 用友能否再引领

用友BIP

用友iuap 用友技术大会 升级企业数智化底座

从入门到精通,超详细的程序员Java学习路线指南

Java你猿哥

Java 数据库 Web ssm 死磕 Java 基础

戴尔科技园动力计划,携手中南高科赋能中小企业数字化转型

科技热闻

Rust-Shyper:基于 Rust 语言的高可靠、开源嵌入式 Hypervisor

openEuler

Linux rust 操作系统 虚拟机 嵌入式

聊聊「低代码」的实践之路

Java 架构 低代码

用友iuap 让企业数智化能力深入、让业务价值浅出

用友BIP

用友 用友iuap 用友技术大会 数智底座

React Native 原生混合路由解决方案_语言 & 开发_微医大前端技术_InfoQ精选文章