专栏名称: 携程技术
携程技术官方账号,分享交流成长。
目录
相关文章推荐
字节跳动技术团队  ·  ByteBrain团队EuroSys25 ... ·  昨天  
InfoQ Pro  ·  充电计划 | 反卷“大”模型 ·  昨天  
51好读  ›  专栏  ›  携程技术

干货 | RN框架在携程旅行鸿蒙应用的全业务适配实践

携程技术  · 公众号  · 架构  · 2024-11-29 16:00

正文

请到「今天看啥」查看全文


  • 已实现社区常用的三方库

  • 自定义组件和API需要应用开发自行实现

  • 差异化工作:
    1)自定义组件和API实现
    • 100+自定义组件和API,基于鸿蒙原生开发实现,再封装提供给RN调用

    • 按优先级分阶段实现这些自定义组件和API,保持上层JS接口不变

    2)RN工程改造
    • 添加react-native-harmony和react-native-harmony-cli依赖库

    • 适配Platform.OS,Platform.select等API

    • 实现xxx.harmony.js文件,逻辑与IOS保持一致

    • 升级三方库版本,如react-native-gesture-handler,从1.X版本升级到2.X版本

    • 三方库版本升级后,对不兼容的地方做适配

    3.3 原生组件开发

    携程CRN框架经过近8年的迭代,业务线非常复杂,自定义的组件、turboModule有100多个。
    在鸿蒙中适配CRN,首先面临的工作就是将这些自定义组件、turboModule在鸿蒙原生端用ArkTS重新实现。
    我们面临以下几个挑战:
    1)工作量
    这些组件经过了近8年的迭代,开发负责人可能几经易手。有些复杂组件,如信息流组件、自定义地图、日历组件、多媒体组件等,逻辑异常复杂,经过跟原开发负责人、产品等初步讨论,工作量都超过单人一个半月。而我们面临的是100多个组件、turboModule的重实现。

    2)HarmonyOS Next逐步完善,与Android、iOS在某些特性上有差异

    开发过程中发现了很多HarmonyOS Next功能不完善、存在若干Bug的地方,毕竟是一个新系统,我们与华为同学紧密合作,一一解决了问题,这个过程见证了鸿蒙系统的愈发成熟。

    出于安全考虑, 鸿蒙系 有一些新特性,比如选取图片视频进行编辑的场景,在Android、iOS中,申请用户权限之后便可以拿到整个系统相册的图片视频,这确实可能存在一些安全隐患。鸿蒙在最开始就切割了这一操作,即使App经用户同意申请了读相册权限,也无法拿到系统主相册的图片视频,本意是让App直接跳到系统相册选取图片之后返回,只提供当次选中的图片信息给App,从而彻底断绝了App侵犯用户隐私的可能。

    但我们的多媒体场景比较复杂,用户选取图片、视频后会跳入编辑页,且可以重回相册页选择其他图片,也就是说我们的图片视频选择页与编辑页存在联动,鸿蒙提供的这种跳入系统相册的方式显示无法满足我们的需求。

    后续经过讨论,鸿蒙提供了相册Picker的方案,将系统相册页封装为组件提供给开发者,我们的图片视频选择页可以内嵌相册Picker,从而解决了联动的问题。但这个需求从开始评审、开发、测试到最终实现,花费了几个月的时间。

    3)RN组件C化

    在接入RN的过程中,发现鸿蒙中RN关键性能指标与Android、iOS有差距,华为鸿蒙RN团队为了解决性能问题,提出了组件C化的方案。
    简单来讲,就是将ArkTS实现的组件用C-Api重新实现一遍,华为方面给出的要求是 容器结点(RN代码中存在标签<>>嵌套的组件)需强制C化。 虽然携程中这种必须C化的组件并不多,但也带来了非常多的适配工作。 具体可参考下篇-组件C化。
    部分组件图如下:

    Fabric、TurboModule
    最开始,我们在实现相关Fabric、TurboModule的时候,鸿蒙RN框架还没有提供Spec文件CodeGen工具,全靠手写。不过现在已经提供了相关工具,具体操作步骤可以参考相关文档。
    Spec文件生成之后,剩下的工作就是相关组件、TurboModule的功能桥接实现,逻辑较为简单,实现相关功能就好。
    需要注意的是:
    • RN代码中存在标签<>>嵌套的组件被视为容器结点,此类型组件需使用C-API实现。

    • 可以通过this.ctx获取RNOHContext,进而获取RNInstance,从而获取一系列RN端JS传入的信息,如View宽高、style等,也可执行发送事件、接收事件、获取TurboModule进行其他操作等等。

    • 在RNInstanceImpl构造函数中有一个arkTsComponentNames字段,可以传入所有我们自定义叶子结点Fabric组件的名称,用于在RNOH SDK内部进行指令分发优化。实现ArkTS端Fabric组件后,需要将Fabric组件的名称加入此列表中。

    • 假设存在实现过于复杂或者其他原因无法C化的容器组件,RNOH SDK内部指令优化代码需修改(这也意味着RNOH SDK需重新打包编译),关键代码见下文‘性能优化-5.3 RN 指令精简章节。

    3.4 组件C化

    经过与华为的详细沟通,RN代码中存在标签<>>嵌套的组件被视为容器结点,此类型组件需强制C化。
    也就是此类型的组件:



    RNComponent算为容器结点

    经确认,携程端存在四个需强制C化的容器结点组件,分别为:

    名称

    描述

    SwipeoutView
    可滑动组件
    ScrollView
    滚动组件
    CustomScrollView
    自定义列表组件
    CRNModal
    modal容器

    简而言之,需要把ArkTS端实现的组件用C-Api再次实现。

    3.4.1 CRNModal C化

    CRNModal 在开发测试过程中一步步探索了实现方案,经过多轮测试、方案讨论调整,最终确定了C化方案。

    方案一:尝试使用系统Modal实现这个组件
    后续测试过程中发现系统Modal的实现方案为系统Dialog,层级很高,携程业务线会出现这样一种场景,RN页面打开Modal后点击跳转一个其他页面,新打开的页面会出现在Modal的下方,不符合需求,方案淘汰。
    方案二:尝试通过新跳转一个透明页面的方式实现modal
    测试发现新跳转一个页面后,RN的点击事件分发出现问题,无法响应任何事件。且我们App的路由方案为Navigation,经与华为方面沟通,Navigation C化难度非常巨大,短时间不可行。此方案淘汰。
    方案三:尝试在RN JS端创建modal
    JS端创建一个style为position: 'absolute', zIndex: 999的容器,层级提高,显示在其他组件上方来实现modal。测试发现调用显示Modal的地方很多,可能会在一个嵌套很深的层级中,如果在这里尝试展示这个zIndex: 999的容器,还是会有被遮挡的情况,最终此方案也被淘汰。
    方案四:C++层进行插入
    经过内部讨论,这个modal应该展示在整个RN页面层级的最上方,这在Android、iOS中都很好实现,但鸿蒙是一个声明式的语言,无法拿到页面实例,无法拿到父组件,也就无法进行插入。
    但研究RNOH SDK之后发现,C化后的RNInstance实例在C++端持有一个XComponentSurface,所有RN页面对应的Native组件都被添加显示在这里,而XComponentSurface可以获取rootView实例ComponentInstance,这是一个根控件,将这个根控件强转为ViewComponentInstance之后,在ViewComponentInstance.cpp代码中可以类似Android,获取childCount,通过index添加child等等,进而可以实现在RN页面层级最上方添加modal,最终也是依据此方案,实现了CRNModal组件。
    流程如下:






    请到「今天看啥」查看全文