动态化-鸿蒙跨端方案介绍
一、背景
👉 华为在2023.9.25官方发布会上宣布,新的鸿蒙系统将不再兼容安卓应用,这意味着,包括京东金融APP在内的所有安卓应用,在新的鸿蒙系统上将无法运行,需要重新开发专门适用于新鸿蒙系统的专版APP。
二、原生适配方案
原生适配方案就是将京东金融APP所有业务层及基建层全部使用鸿蒙语言重写,但该方案存在以下三个问题:
1、首次开发成本高:对齐金融APP当前能力,1:1开发鸿蒙版,开发周期长,研发投入巨大。
2、业务迭代成本高:未来,无论是存量业务还是新增业务,都需要在iOS、Android、Harmony等多端同时进行,产品沟通、开发、测试、UI验收成本均会升高。
3、业务发布效率低:业务需求完成后,需要在华为市场提交、审核、发布,发布周期长,且无法做到业务随时发布。
三、动态化适配方案
“动态化”是一个由京东金融大前端团队全自主研发的,一份代码,可以在iOS、Android、Web三端运行的跨平台解决方案。
1、方案简介
动态化目前已经具备一份代码在iOS、Android、H5三端运行的能力,该方案就是将动态化一码多端能力对接到鸿蒙系统,降低首次适配研发投入;一次开发,四端共用,长期降低业务迭代成本;并且使业务具备随时发布能力。
2、方案实现
在鸿蒙系统实现动态化的流程和安卓端流程相似,但因鸿蒙生态尚未成熟,我们面临着譬如V8虚拟机不能直接使用、核心能力层通讯过程复杂、布局库需要移植等一系列难题。
如上图简略所示,动态化在鸿蒙系统的跨端实现大致流程如下
虚拟机层-V8
动态化跨端框架的实现依赖一个能够执行js代码的虚拟机,在iOS端使用苹果系统提供的JSCore,在安卓端使用V8,而鸿蒙系统未提供类似JSCore或者V8的虚拟机,所以我们需要将V8移植到鸿蒙系统,对应上图V8 For Harmony部分。
虚拟机对接层
完成V8移植后,我们要使用ArkTS语言进行V8接口的包装和调用以便使用,包括虚拟机对象创建、内存管理、通讯管理等一系列能力,对应上图ArkTs2V8部分。
动态化引擎运行
完成ArkTs2V8后,我们就可以运行RomaEngine文件了,RomaEngine文件是一个js文件,核心职责在于能够生成一颗虚拟Dom树(V-Dom),以及进行V-Dom树对比从而触发相应页面节点的更新。
通讯层-JSI
RomaEngine产生V-Dom树的过程会逐条触发原生渲染树的节点创建,在iOS和Android端目前是使用JSON描述的方式进行通讯,但在大量数据传输场景存在性能瓶颈,虽然我们使用了一些技术手段进行了优化,但实现成本高,开发者体验差,所以在鸿蒙系统我们决定使用业界先进的JSI技术来建立JS和原生(C++)通讯,对应上图通讯层JSI部分。
原生SDK层
通过JSI技术我们就可以在C++语言中收到JS发送过来的节点创建的指令,而鸿蒙原生UI的语言是ArkTS,所以需要借助鸿蒙系统提供的NAPI接口进行C++和ArkTS语言的通讯,对应上图NAPI部分,这样我们就实现了JS→C++→ArkTS链路的通讯,当然也需要反向通讯的过程,这两个过程还包括同步通讯、异步通讯等能力,这里就不详细展开了。建立通讯通道后,再借助鸿蒙系统提供的自定义组件嵌套能力,就可以递归形成鸿蒙原生UI树。
布局层
我们先将Yoga库移植到了鸿蒙系统,在上述形成的鸿蒙原生UI树并未做任何的布局处理,借助Yoga布局就可以计算出所有UI元素最终的位置和大小,这样就完成了整个渲染流程。
交互处理
例如页面上渲染出来的一个按钮,当发生点击事件后,我们需要实现ArkTS→C++→JS通讯链路,将点击事件传递给业务方。
3、关键技术
1、V8虚拟机移植
- 自编译V8路线
V8虚拟机移植到鸿蒙系统是一个动态化必备的高技术门槛卡点任务,若无法突破此任务,动态化鸿蒙系统的跨端则无法实现。 然而V8是一个近千万级代码的庞大仓库,需要掌握CMake、Clang、LLVM、Ninja等一系列交叉编译知识(嵌入式范畴),对于应用开发者是一个巨大的挑战,通过动态化小组成员的攻坚克难,现已掌握了V8虚拟机交叉编译移植技术。
- 华为内置V8路线
短期看我们初步掌握了V8交叉编译移植技术,但从包大小、稳定性、兼容性、维护成本等维度看,华为厂商内置V8是一个具有长期收益的重大事项,通过和华为持续沟通,最终华为将V8内置到了操作系统,业界所有类动态化框均可直接使用内置V8虚拟机进行跨端框架的适配。
2、通讯方案设计
鸿蒙系统提供了NAPI的方式来建立Arkts和C、C++的通讯。动态化的JSI通讯,建立了JS虚拟机和宿主环境C++语言的通讯。这样我们就可以建立JS、C++和ArkTs三种语言间的通讯了。
3、页面渲染方案
- 首次渲染
页面渲染的核心流程就是对于三棵树的管理过程,RomaEngine负责产生V-Dom Tree;通过JSI通道从根节点开始按照父子关系发出ComponentTree节点创建命令,最终形成一个和V-DomTree结构一致的ComponentTree,ComponentTree每个节点都包含了样式、属性、内容等信息;最后通过鸿蒙系统提供的自定义组件嵌套方式将ComponentTree映射为RenderTree,这样就完成了使用鸿蒙原生组件渲染。
- 二次渲染
当业务需要更新页面的时候,会根据新的页面数据重新生成一个新的V-Dom Tree,和页面旧的V-Dom Tree进行对比,最终得到需要更新的节点数组,将这个数组同样通过JSI通道发送到Componet Tree对应的节点,再查找出在Render Tree对应的节点完成页面的节点更新。
4、布局方案
如果节点不经过布局计算,是无法在屏幕正确的位置上显示的,Yoga库是一个跨平台布局计算库,目前动态化在iOS和Android端均使用此库进行布局计算,为保证鸿蒙端布局效果和另外两端的一致性,我们成功将Yoga库编译成了鸿蒙系统可运行的库,借助Yoga进行节点布局计算。
5、更多内容
通过以上流程就完成了一个页面渲染的核心过程,每一个环节都比较复杂,后续我们会以系列文章展开讲解。
除此之外,还需要处理交互事件、动画、生命周期、埋点曝光、组件化、图表等一系列功能,后续也会加入系列文章中。
四、未来规划
自绘方案
除了鸿蒙系统,小米、Vivo也发布了澎湃OS、blueOS,如果将来也不兼容安卓,动态化在每个系统都要做一遍和鸿蒙适配类似的工作,并且需要多个端同时长期维护。我们将探索基于SKIA技术的自绘制技术,该技术可以实现一份渲染代码,实现在iOS、Android、HarmonyOS、澎湃OS、blueOS以及未来新的系统上的渲染。
转小程序
动态化基于V-Dom模式实现跨端的渲染架构,可以实现同样一份代码转换为微信小程序、抖音小程序、百度小程序等,使业务可以低成本快速完成私域投放。
生态扩展
未来的终端设备将形成万物互联的世界,比如华为的手机应用和车机间已经可以无缝流转,动态化将持续探索在更多设备上运行的技术方案!