干货 | 携程APP Native/RN内嵌Flutter UI混合开发实践和探索

本文探讨了在React Native(RN)中嵌套Flutter View以及在原生(Native)应用中嵌套Flutter UI的实践,旨在解决多技术栈共存场景下的业务需求。作者通过分析现有技术栈的优劣,提出了在RN内部和原生列表中嵌入Flutter的解决方案,并详述了遇到的问题和解决方案,包括事件传递、页面生命周期管理和业务交互等关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者简介

 

Deway,携程资深工程师,iOS客户端开发,热衷于大前端和动态化技术;

Frank,携程高级工程师,关注移动端热门技术,安卓客户端开发。

前言

随着各种多端技术的蓬勃发展,如今的移动端和前端早已不再拘泥于自身的边界,而是不断延伸、扩展和融合,逐步向着真正的大前端技术迈进。跨端技术也从早期的Cordova/PhoneGap、纯H5页面发展到如今的ReactNative(以下简称RN)、Weex、小程序、Flutter群雄并存的局面。各种技术栈各有优劣和特点,技术选型需视团队自身情况而定,没有绝对好坏之分。然而在实际开发中,并不是只选用一种技术栈,那么研究多种技术栈融合和嵌套使用的就有了迫切的必要性。

本文我们从实际业务场景出发,初步实践了在RN里面嵌套flutter view、在native里面嵌套flutter view,探索其可行性,并回顾这个过程中遇到的一些问题和解决方案。

一、背景

1.1 现状

随着时间的推移,携程app中酒店列表和详情两大页面已经全部转为flutter技术栈,初期的使用场景也比较单一,只在主流程使用。然而业务不断迭代之后,flutter页面在其他流程使用的频次也越来越高,比如列表页面,作为酒店一线SKU产品展示的主页面,复用的需求非常旺盛和迫切。那么此时需要思考更多的通用性和可移植性,以适用于在不同的场景不同的技术栈页面嵌入使用。

1.2 两大场景

1de24e26ea4df9e48b9b380c5da0693a.png

bca782b5cf90cb450a2dc5d592be2b40.png

  • 场景一:上左图为携程大搜页面的酒店列表。在本次技术改造之前,大搜页面的酒店列表和酒店主流程的列表大相径庭,差异不光是在UI展示方面,酒店频道列表的信息和优惠更加完整,价格体系也更统一。大搜的技术栈是RN,而酒店列表技术栈是flutter,如果想要统一无非两种途径:1)查漏补缺追平RN侧业务;2)将flutter酒店列表打包嵌入RN页面。

  • 场景二:上右图为查询页钟点房标签下的钟点房列表,查询页目前还是native技术栈,那么此时也必须考虑将flutter列表页嵌入native页面。

对于不同技术栈的业务场景,不断为多侧业务同步补齐功能,维护成本是相当巨大的。对于酒店列表业务来说,唯一可选的路径就是在大搜和酒店主频道等业务场景中共用一个列表,甩开历史包袱,实现真正意义上的业务对齐。所以,基于以上两个场景,我们初步探索了flutter页面在多种复杂结构的嵌套使用,即RN中嵌套flutter、原生ListView中嵌套flutter,并将解决方案记录在本文中,为之后可能遇到的多业务场景提供一个思路。

二、RN中使用Flutter

2.1 可行方案的探究

在接到这个嵌套需求的时候,考虑到成本最低的方式是直接在大搜页面层上盖列表,即在切换到酒店tab的时候将flutter view盖在上层。实际上在思考利弊之后,放弃了这个方案。有如下几个弊端:

  • RN无法单独控制flutter view层的展示, 需要通过层层事件通知,复杂且繁琐

  • RN需要计算出上盖offset的偏移值,在不同屏幕尺寸存在偏差

  • 在不同tab切换的时候,flutter控制器生命周期难以及时被同步

基于上述的几个问题,那么考虑的方向就偏向于直接把flutter view包装成RN的Component使用。

2.2 Native Components的原理

我们先简单回顾下RN的启动流程(以iOS为例)。

b4d8ac908b3f2acf8a5657dee0b55431.png

RN启动流程

  • 程序启动完成的时候创建了根视图RCTRootView,负责展示所见内容的根容器

  • 创建管理native和js的交互的桥接对象RCTBridge

  • 创建RCTBatchedBridge批量桥对象, 这个类是负责交互通信的核心

  • 加载所有自定义的native modules。这些modules最终会被转为RCTModuleData类型,包含方法列表、队列等信息,并缓存到全局的模块配置信息表中

  • 通过jsExecutor将native创建的模块表注册到js端

  • 开始异步加载js代码,执行完成后通知到RCTUIManager去调用对应的native组件进行渲染

这里省去了一些非关键步骤,可以看到RN本身是支持调用native原生组件的,调用native UI components这一步比较关键的是RCT_EXPORT_MODULE。这是一个宏定义,重写了load方法,在其中调用RCTRegisterModule方法。再看看RCTRegisterModule的实现,其实就是将moduleClass注册到一个全局容器。

/// iOS
#define RCT_EXPORT_MODULE(js_name)          \
  RCT_EXTERN void RCTRegisterModule(Class); \
  +(NSString *)moduleName                   \
  {                                         \
    return @ #js_name;                      \
  }                                         \
  +(void)load                               \
  {                                         \
    RCTRegisterModule(self);                \
  }
/// iOS
void RCTRegisterModule(Class moduleCl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值