【AICon】探索八个行业创新案例,教你在教育、金融、医疗、法律等领域实践大模型技术! >>> 了解详情
写点什么

去哪儿网 ReactNative 跨小程序多端方案介绍

  • 2021-03-08
  • 本文字数:5214 字

    阅读完需:约 17 分钟

去哪儿网 ReactNative 跨小程序多端方案介绍

1 前言

qrn-remax-unir 是由去哪儿网前端技术团队实现的一套将 RN 适配到小程序端的跨端组件,通过该组件库可快速方便的将 RN 源代码直接运行到小程序端。方案参考了 react-native-web 的适配方案,使用 remax 框架来实现适配组件库并达到适配多小程序的目的。和 react-native-web 一样,它对 RN 源代码侵入度低,并且调试和替换组件相当方便。


方案来自于社区,我们只是合理的应用用来解决我们遇到的业务问题,最终开发了这套组件库,也希望开源出来跟大家分享和共同探讨多端开发之路。


下面我们简单介绍下 RN 到小程序的适配方案和适配组件库的点滴。

2 多端方案回顾

qrn-remax-unir 组件库是整个去哪儿网跨端方案的一个部分,通过整套方案可实现将 RN 代码直接运行到 H5 和小程序,达到跨 IOS,ADR,H5,小程序的目标。整体多端方案的思路是:


  1. 使用 react-native-web 将 RN 代码适配到 H5 上运行,这也是 RN 官方推荐和集成的方式。

  2. 在 remax 组件的基础上实现一套 RN 的组件库,借用 remax 来适配到多端(qrn-remax-unir)。

  3. 借助 webpack 的特性来实现针对不同平台的打包。


3 RN 相关多端方案

3.1 对 alita 的调研

在最初的调研中我们注意到 alita 可以实现将 ReactNative 转换到微信小程序运行,也对方案进行了详细的调研:


  1. alita 会在编译阶段将 JSX 语法按照代码块编译成微信 wxml 的碎片,然后用 templete 包裹;

  2. 内部实现了一个 mini-react 来对接适配 react 和小程序的生命周期。


详细原理可参考:


https://zhuanlan.zhihu.com/p/69333351


https://www.jqhtml.com/44555.html


于是跑了些 demo 对方案进行使用觉得还是跟我们的期望有些差距:


  1. 虽然期望是对 RN 代码无入侵,但还是会对 RN 源码有限制的,部分特性不能用,动画之类的要求用 alita 提供的自定义动画库;

  2. 内部使用了自定义的 mini-react 来对接 react 和小程序的生命周期,考虑后期对 react 新特性的适配进度风险;

  3. 专注于 RN 到微信小程序的转换,对其他小程序不支持。


基于以上原因我们最终没有直接使用该方案,调研过程感觉他们对 jsx 模板的处理思路还是很新颖的,是很好的借鉴。

3.2 remax 简单原理

remax 可实现在小程序中用真正的 react 进行开发。remax 将自己实现成了一个 react 的渲染器,收集宿主 UI 变更指令生成页面 VNode 树,然后在小程序渲染层渲染这个树。


详细原理可参考:https://juejin.cn/post/6844904131157557262


由于基于运行时适配的方案,有以下优缺点:


  1. 适配在 react 虚拟 dom 之上,对 react 的技术栈无任何限制,redux,mobx,hooks 等都可自由使用;

  2. 模板的动态处理在渲染的时候可能效率低下,需要针对性解决;

  3. 由于没有编译处理,运行时都是平台源代码,查问题更方便;

  4. 基于 react 组件,可以很好的对小程序原生组件进行支持;

  5. 并没有提供对各个小程序的跨端组件,只对部分基础组件进行了封装和适配。

4 我们的适配方案

remax 虽然支持 remax 的语法,但是他是基于自定义组件提供的语法 DSL,提供的组件和 RN 也没有任何关系。但他们对 react 语法适配到小程序的方案还是很大胆实用的,也启发我们可以按照类似的适配方案来实现 RN 组件到小程序的适配,这样就可以将 RN 运行到小程序了。

4.1 ReactNative 到 remax 组件

调研 remax 的适配方案,虽然方案原理说起来很简单,但是真正要做这么一套东西评估了下还是非常耗时耗力的。


重新评估下来,发现 remax 其实已经可以做到 react 到小程序的适配,且提供了基础的几个跨端组件可供使用。我们直接用 remax 组件来实现 RN 的组件则可以快速的适配到小程序端,虽然可能带来部分性能损耗。


看个将 RN 的 Text 组件适配到 remax 组件的例子:


4.2 ReactNative API 的适配

对与 API 的实现要更为简单直接一些,这里请允许我将 react-native 的组件分为两类:


其一 是纯函数的 api,简单理解就是你调用了一个由框架提供的函数,得到了你想要的数据写入或返回,比如 Dimensions,这一类普通 api,qrn-remax-unir 的处理方案就是能够通过封装调用小程序提供的 api 并存在两个平台磨平参数差异可能的即可完美适配。对无法通过调用小程序 api 来实现同样效果的或小程序场景逻辑上就不存在的,qrn-remax-unir 往往通过空实现并对开发者加以告知。


其二 是调用一个有框架提供的方法,在页面上进行呈现,我们姑且叫它 api 组件(react-native 中是 api、但在小程序平台更像是组件),例如:Alert、ToastAndroid、ActionSheetIOS 等,这一类 api 的实现方案是构造展示的模板组件,暴露出方法能够间接修改组件的状态,例如 alert 就是通过获取调用方法传入的内容进行填充,当获取用户操作后修改为隐藏不显示的状态并回调组件的回调方法。

4.3 复杂组件和 API 的适配

复杂组件和第三方组件其实都是对基础元素组件的组合使用,我们从最底层的基础组件(View Text 等)完成适配,这样大部分复杂组件都可以直接适配到小程序端。如下图只要 qrn-remax-unir 的基础组件适配得足够完整就可以保证对上层 RN 业务和组件的完整适配。


5 开发过程

虽然开发思路大体清晰了,但在开发过程中还是遇到了一些比较棘手的问题。

5.1 样式处理

对于将 RN 的样式转换成小程序端能用的样式,我们一开始确定了两个方向:


  1. 编译时提取并转换

  2. 运行时动态生成


编译时提取并转换


这个方式其实是我们一开始经过讨论觉得可行的方案,具体方式就是通过编写 Webpack 以及 Babel 插件,实现在编译阶段对样式相关对 RN 代码进行抽取并生成最终的 WXSS 文件。


这个方案的好处就是:


静态编译出的文件可以更好的进行管理,对于样式转化出的问题可以直观的进行修改,相当于有一个可见的原生产物去进行调试,对于开发者显得更友好,更直观。


实现的效果理想中是这样的。


对于源代码:


const styles = StyleSheet.create({    container:{        width:100,        height:100    }}) <View style={styles.container}>    <Text>Hello World</Text></View>
复制代码


处理后生成的 styles.wxss 文件中:


.container-test {    width:100px,    height:100px}
复制代码


然而在尝试开发好了相关 babel loader 以及 webpack 插件以后,面对真实的复杂项目时,却发现代码的书写复杂情况很难穷举解决。


因为 RN 代码的样式并不总是规矩的写成:


const styles = StyleSheet.create ({    key:value})
复制代码


在项目中由于一些样式的值,例如屏幕宽高等,需要在运行时获取,于是会有一些不规则的赋值形式:


const height = DeviceInfo.isAndroid?100:120;const styles = StyleSheet.create ({   height})
复制代码


当出现这种动态获取运行时值的情况时,我们的这个策略就无法处理了,于是这个方案只能暂且作罢。


运行时动态生成


这种方案的基本实现方式其实是借鉴了 React-native-web 的做法,也许 Twitter 也尝试过编译时去生成 CSS 文件转换到 web 的方案,最后未果,才使用的运行时提取 RN 样式成 class 并赋值到 DOM 元素上的方案。当然,通过分析了 react-native-web 的源码库,我们做了一定程度的改动以适配到微信小程序的情况。具体做法如下:


以最基础组件 View 为例:


import { View , Text } from 'react-native';
```<View style={{flex:1}}> <Text>Hello World</Text></View>```
复制代码


进行完转换的 className 以及 style,会随同一些默认补全样式,传递到 Remax 的 View 组件中对于一个普调的 View 组件,我们按照 RN 正常书写习惯,对 style 赋值。我们适配层做的核心处理,就是将这些 styles 解析,并且转换和处理 Class 以及数组格式的样式,生成 classList 以及 style 变量。


const convertStyle = (styles) => {    const classList = [];    const style = {};    const convert = (value) => {        // 对于Class,直接增加进classlist        if (typeof value === 'string') {            classList.push(value)        } else {            // 对于数组,递归处理每一个元素            if (Array.isArray(value)) {                value.forEach(item => {                    convert(item)                })            } else {                // 对于一般的属性,直接转换成行内样式                value && Object.assign(style, inline(value))            }        }    }    convert(styles)    return {classList, style}}
复制代码


进行完转换的 className 以及 style,会随同一些默认补全样式,传递到 Remax 的 View 组件中。


// 默认样式supportedProps.className = "view-default " + classList.join(" ");supportedProps.style = style;supportedProps.id = this.props.id;return (<RemaxView {...supportedProps}/>)
复制代码


至此在运行时的 Dom 渲染,就会得到相应的 class 名以及行内 style 的值。



所以,对于编译时遇到的,那种 DeviceInfo 这类赋值,也会在运行时得到最终的值并添加到组件的 style 属性里,从而解决了编译时无法控制的事情。


样式小结与思考


对于样式的处理,有很多细节需要注意,例如对于不同端的单位转换问题,对于不同端一些默认样式的补全的设置等。此处重在方案的选择过程介绍,并未列出具体样式差异,还需要更多的人来贡献力量,持续投入,跟进 react-native 的版本以及 remax 的版本。而且对于 StyleSheet 的细节处理,感兴趣的同学也可以去查看 react-native-web 的源码,还是值得对跨端开发感兴趣的同学深入研究学习的。关于方案,我们也在思考是否可以更进一步提升,比如将编译和运行时结合,从而减少行内样式,目前这样直接写入行内样式还是会导致我们的 dom 元素上属性值过长,不可读,不利于开发调试。另一方面,这种过长的属性也使小程序端的性能表现受到了一定的影响。

5.2 对动画的处理

qrn-remax-unir 在实现动画方案上,采取了尽量不引入新的写法,与 react-native 原本写法尽量保持一致的思路,对 RN 代码做到零入侵。


这里准备了一个 demo,代码中的动画写法和 react-native 官方文档的写法是一致的,先看一下效果。


视频地址


在定义 react-native 的单一动画是这样写的:


Animated.timing(    this.state.opacity,    {        toValue:1, // 1        duration:3000, // 2        easing:Easing.ease // 3    }).start(); // 5
复制代码


qrn-remax-unir 将上面的代码转换成类似下面的能够在小程序运行的代码,1-5 的动画关键信息通过框架层处理成一一对应,过渡时间就是 react-native 的动画时间即 duration,opacity 就是 react-native 的 Animated 组件的动画样式 key 即 opacity、linear 就是 react-native 中的赋值 API 即 Easing(有一些复杂曲线难以适配会在小程序端做相应的降级处理,比如使用 linear),初始值和目标值直接传递过去就可以了再利用插值器将原始单位正则解析出来放如动画属性值中,产物就是这样的 transition: 3000ms opacity cubic-bezier(0.42, 0, 1, 1);


组合动画、平行动画和顺序延迟动画都是由 Animated.timing 组成动画序列,由 react-native 的 Animated 本身的处理机制处理多个动画触发和销毁。

6 组件库的使用

组件库地址:https://github.com/qunarcorp/qrn-remax-unir


组件 demo 地址:https://github.com/qunarcorp/qrn-remax-unir-demo


组件文档地址:https://qunarcorp.github.io/qrn-remax-unir/#/./


想要了解具体如何使用我们的组件库,可以下载我们的示例工程进行开发学习:传送门(https://github.com/qunarcorp/qrn-remax-unir-demo/tree/master


这个工程内集成了 RN,web,微信小程序三端的编译开发能力,并且启动十分简单,你可以基于这个项目进行跨端项目的改造。此项目开发时效果如下图(自左至右:RN->Web→微信小程序):



项目启动过程很简单,进入到项目根目录下:


1、安装依赖


yarn
复制代码


2、运行 dev 环境


yarn dev         //RN,web环境yarn dev:wx      //微信小程序,需要用小程序IDE打开./dist/wechat目录进行调试开发
复制代码


此时修改代码就可以实时热更新每一端的代码,是不是很方便!赶快开启你的跨端开发之旅吧!


如果你想了解具体搭建过程,也可以参考我们 github 网站上的介绍:传送门(https://qunarcorp.github.io/qrn-remax-unir/#/./),尝试自己去动手改造出这样一个跨端项目。


作者介绍


冯地木


去哪儿网前端技术总监


08 年开始从事前端工作,曾就职于人人网、新浪微博、爱奇艺等,12 年加入去哪儿网,主导多次前端技术架构升级,推进 Node 前后端分离,React,RN 等技术架构在业务上的落地应用,擅长各种前端性能优化和工程化实践,目前负责推进 Qunar 的多端统一化升级方案。


孟晨


2019 年加入去哪儿网,擅长多种前后端语言,主要负责 Node 工程化,规范化工作,现阶段工作重心为多端统一框架的开发与推广。


王佳峰


2019 年加入去哪儿网,主要负责公共产品业务向 RN 技术栈迁移以及主流程 RN 工程向三端工程迁移。主要涉及 React-Native、Touch、小程序业务开发和多端融合框架等基础架构的研发。


本文转载自公众号 Qunar 技术沙龙(ID:QunarTL)。


原文链接


去哪儿网 ReactNative 跨小程序多端方案介绍

2021-03-08 18:427155

评论 3 条评论

发布
用户头像
2021-03-08 15:18
回复
??
2021-03-08 15:39
回复
里面嵌套了HTML出了些问题,已经修复。
2021-03-08 18:47
回复
没有更多了
发现更多内容

瓴羊Quick BI跻身Gartner魔力象限挑战者行列

夜雨微澜

MES系统在机器人行业生产管理种的运用

万界星空科技

人工智能 机器人 MES系统 机器人自动化

HA3 SQL样本实验:一种混合计算查询的全新样本解决方案

阿里技术

简明易懂的介绍:Selenium是什么?

Liam

编程 测试 自动化测试 web开发 测试工具

文件传输软件常见问题解决办法大全

镭速

文件传输软件

文心一言 VS 讯飞星火 VS chatgpt (73)-- 算法导论7.1 4题

福大大架构师每日一题

福大大架构师每日一题

好玩有趣的HTML标签

专注前端开发

html

山东布谷网络科技详解直播打赏源码,让功能更灵活

山东布谷网络科技

App 直播源码

镭速-解析极速文件传输软件

镭速

文件传输软件 传输文件

告别传统人肉运维,实现360°可观测!奇点云数据存算引擎DataKun R2.0发布

奇点云

产品发布 奇点云 数据安全引擎 数据存算引擎

智慧生活的下半场,从全屋智能4.0接入未来

这不科技

华为 鸿蒙系统

关于低代码解放程序员这件事儿

互联网工科生

低代码 可视化开发 企业级应用程序开发 JNPF

Rust“巨坑”?真相来了!

这我可不懂

rust 编程语言 后端

基于昇腾,安擎又双叒叕推新品!

科技热闻

推动多云管理平台发展的因素简单分析

行云管家

云计算 云管平台 上云

Lasso for mac(窗口管理器) 1.5.6中文版

mac

苹果mac Windows软件 Lasso 图片和屏幕截图工具

HarmonyOS系统级推送服务,打造消息通知新体验

HMS Core

软件开发项目文档清单(多套实际案例)

金陵老街

袋鼠云数栈 DataOps 数据生产力实践,实现数据流程的自动化和规范化

袋鼠云数栈

DataOps

预设成功

FunTester

TooKit助力开发者上云

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 8 月 PK 榜

2023年广州国际智能窗帘及智能门窗遮阳展会

秋硕展览

龙蜥社区系统运维 MeetUp

乘云 DataBuff

企业如何挑选适合自己需求的文件传输软件

镭速

文件传输软件

LED显示屏只显示一半怎么办

Dylan

硬件 显示器 LED显示屏

【智领信创】用友 U8 cloud &亚信科技 AntDB联合产品强势来袭,0元购活动惠及陕、鲁

亚信AntDB数据库

数据库 AntDB AntDB数据库 企业号 8 月 PK 榜

IPQ5018-IPQ4019-IPQ6010-support WIFI technology-MESH-FAST ROAMING

wifi6-yiyi

mesh FASTROAMING

如何优雅地处理RabbitMQ中的消息丢失

互联网工科生

RabbitMQ 消息系统 消息不丢失

2023年-广州国际睡眠家居产品及睡眠展会

秋硕展览

腾讯云ES:一站式配置,TKE容器日志采集与分析就是这么简单

腾讯云大数据

ES

Photoshop 2023 (ps 2023) for Mac v24.6/25.0beta激活版

mac

Photoshop 2023 PS2023 修图软件 苹果mac Windows软件下载

去哪儿网 ReactNative 跨小程序多端方案介绍_大前端_Qunar技术沙龙_InfoQ精选文章