AIGC 应用、数据分析等企业 10+ 热门专题课,就在极客时间企业版>>> 了解详情
写点什么

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

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

    阅读完需:约 17 分钟

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

AI 大模型超全落地场景&金融应用实践,8 月 16 - 19 日 FCon x AICon 大会联诀来袭、干货翻倍!

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:427307

评论 3 条评论

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

运营商系统快速上云的实践分享

鲸品堂

架构 系统 运营商 上云 企业号 5 月 PK 榜

AI日报|苹果将在iOS 18中引入ChatGPT,联想或成AI PC最大受益者

可信AI进展

#人工智能

TikTok标签使用技巧,从入门到精通全攻略

蓉蓉

TikTok tiktok直播

研发提效:想快速定制一个OLAP应用?你可以这么做

京东科技开发者

IDEA 最新激活码,激活到2099年,永久激活亲测有效!!!

大师兄

IDEA idea2024激活码 idea激活码 idea破解教程 idea激活教程

区块链技术在供应链管理中的应用与挑战

区块链开发团队DappNetWork

Apifox 更新|编排模式、Markdown 编辑器升级、自动申请 SSL 证书、用户反馈问题优化

Apifox

前端 后端 Apifox API 后端程序员

LLM 大模型学习必知必会系列(六):量化技术解析、QLoRA技术、量化库介绍使用(AutoGPTQ、AutoAWQ)

汀丶人工智能

AutoAWQ AutoGPTQ 大模型量化技术

LLM 大模型学习必知必会系列(七):掌握分布式训练与LoRA/LISA微调:打造高性能大模型的秘诀进阶实战指南

汀丶人工智能

大模型微调 LORA微调 LISA微调

NineData架构师周金义:ClickHouse 数据管理与同步的关键技术

NineData

最佳实践 Clickhouse 数据管理 NineData 迁移同步

国产数据库替代加速 助力数字中国建设

科技热闻

中国程序员和外国程序员到底哪里不一样?

伤感汤姆布利柏

深度合作!博睿数据联合中国信通院开展公网服务质量评估工作!

博睿数据

区块链智能合约

区块链开发团队DappNetWork

ChatGPT指南:含有1000+ChatGPT资源

蓉蓉

ChatGPT GPT-4

掌握postman,开启API测试新纪元!

测吧(北京)科技有限公司

测试

关于Vearch在大模型中使用的一些实践

京东科技开发者

从0到1:广告营销多智能体架构落地全攻略

百度Geek说

生成式AI 企业号 5 月 PK 榜 企业号2024年5月PK榜 多智能体架构

K8s 小白入门|从电影配乐谈起,聊聊容器编排和 K8s

小猿姐

Kubernetes 云原生 容器化

程序员/码农35岁都面临转行或失业?

伤感汤姆布利柏

智能单款计划助力品牌利润增长

第七在线

LLM 大模型学习必知必会系列(三):LLM和多模态模型高效推理实践

汀丶人工智能

大模型 大模型推理

LLM 大模型学习必知必会系列(四):LLM训练理论篇以及Transformer结构模型详解

汀丶人工智能

Transformer 大模型训练

掌握Postman,开启API测试新纪元!

测试人

软件测试 Postman API

大型前端应用如何做系统融合?

京东零售技术

JavaScript 前端 企业号 5 月 PK 榜

万界星空科技电线电缆行业MES解决方案

万界星空科技

mes 万界星空科技mes 电线电缆行业 电线电缆mes

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