当我们讨论动态化时在讨论啥

动态化方向上业界很早就提出并实践了很多成熟的方案。大概经历了以 Webview 为容器承载 H5 的 Hybird 方案。到以 RN 为代表的 RN、Weex、hippy 等前端技术栈映射原生 UI 实体的类 RN 方案。同时以 VirtualView(Tangram)、MTFexBox、 DX、GX 为代表的 NativeDSL 方案在轻交互重展示的卡片场景在也有很多应用。
近些年来 Jetpack Compose 和 SwiftUI 更为现代的声明式 UI 在客户端技术上逐渐流行起来,也给跨端和动态化带来了新的可能。

1 类 RN 方案

执行 JS 脚本用以组织渲染的布局树。性能瓶颈在 JS 执行构建 dom 树 和 JS 通信上。
RN 、 Weex、Hppiy 、Hummer 是其中的典型代表。

1.1 ReactNative

  • 基本原理:React- > V-DOM -> Native layout

  • 线程模型:JSThread,UIThread,ShadowThread。

    • JSThread:JavaScript 线程,负责 JS 和原生代码的交互线程,大部分的逻辑都在此执行。
    • ShadowThread:构建 V-DOM,交付 UIThread 在原生平台上渲染。
    • Native 交互: Android/Platform 的 UI thread;

新旧对比架构
RN 对整体架构做了一个大的升级,解决长期的以来的性能瓶颈。

Bridge 通信 ReactNative旧版Bridge通信架构图:JS线程与Native线程通过Bridge异步通信 ReactNative新版JSI架构图:JS引擎直接扩展实现同步通信
JS 引擎 旧版JSC引擎运行期解析执行架构图
解析执行是在运行期
Hermes引擎支持二进制加载,解析编译前置到打包期
引擎支持二进制加载,解析编译放在了打包期

引擎直通 去 JSBridge,JSC -> JSI。去掉异步调用,消息队列处理。序列化耗时。
Hermes 引擎 支持二进制加载;针对移动端内存回收。

1.2 hippy 3.0

Hippy动态化跨端三层架构范式图:开发期、解析执行期、渲染期hippy 已经把动态化跨端给范式化了,分为开发期、解析执行期、渲染期。

1.3 hummer

https://github.com/didi/hummer
Hummer跨端框架架构图:JS引擎、JSBridge、YogaLayout、NativeRender四层结构

  • 编码期:写 js 代码、原生渲染。
  • 原生渲染: JSBridge -> YogaLayout -> NativeRender
    JSEngine 执行 JS ,JSBridge 异步调用,利用 invoker,实现 View 树的构建、样式设置、事件设置
  • 业务逻辑与 UI 逻辑 JS 单线程执行的,不维护虚拟 Dom,YogaNode 放在 Native 侧。
  • 事件注册:js 注册 -> objId(callabck) -> native 注册 listener-> 通过 objId 回调 js -> js 真正的执行 callback
  • 线程模型:JSThread 、 UI Thread。

"从这个架构设计可以看出,我们抛弃了业界其他动态化跨端框架普遍使用的 DSL 层和 VDOM 层,因此原生 Hummer 不具备前端开发常用的响应式编程的能力…

1.4 lynx

1.4.1 早期

Lynx早期架构图:DOM节点构建在Native层,JS运行业务逻辑不阻塞UI展示

  • 首屏直出:RN 或 Weex 类型的跨平台框架是在 JS 运行时中去创建、更新 DOM 节点,js 虚拟机承担了大部分的工作。而 Lynx 是将 DOM 节点构建全部放在 Native 层,JS 运行的是业务逻辑、不阻塞 UI 展示,整体轻 JS 逻辑设计
  • 字节的 lynx 早期有开源版本,后来转到内部维护升级,作为字节跨端的重要基建,广泛用在各个业务线。
    Lynx轻JS逻辑设计图:首屏直出,DOM节点Native构建,JS执行业务逻辑
  • lynx 最重要的渲染点在于首屏直出。Lynx 是将 DOM 节点构建全部放在 Native (C++)层。JS 运行的是业务逻辑、不阻塞 UI 展示,整体轻 JS 逻辑设计;
    Lynx自建渲染工具优化架构图:扩展平台便捷及针对性优化
  • 内部有做了大量优化升级,其中很重要的一项是自建渲染工具,扩展平台便捷以及做更为针对性的优化。

1.4.2 如今

2025 年 3 月,lynx 正式开源。https://lynxjs.org

1.5 类 RN 小结

  • RN 以及类 RN 方案能很好的兼顾动态性和多端一致性,但是 【DOM 树的执行组装】 和【不同语言通信】是该类方案的主要瓶颈。
  • 各厂都着重在性能这个象限上做了很多建设,努力的方向最终也是趋同。
    • dom 树构建 左移到研发期。由执行构建变为解析构建。
    • 渲染优化 dom diff;布局拍平优化下移到 c++; 线程模型优化,解析映射组装 dom 逻辑异步+并发;自渲染/自绘;
    • JS 引擎性能 JS 引擎支持 bytecode。
    • 替换 jsbridge 为 JS 引擎的原生扩展。各家叫法不一样有的叫引擎直通,有的 JSBinding 模式。其实都是把原本 JSBridge 的通信方式替换成预埋到 C++ 层直接弥合 JS 与原生通信。

2 NativeDSL

渲染管线使用客户端原生渲染管线,通过协议映射原生控价元素,天然具备 首屏直出。

2.1 MTFlexBox

"MTFlexbox 适用于重展示、轻交互的业务场景,与现有 HTML、React Native、Weex 等跨平台方案相比,MTFlexbox 具备着性能高、渲染速度快、兼容性高、原生功能支持度高等优势。但其缺点在于不支持复杂的交互逻辑,不适合复杂交互的业务场景

项目架构
MTFlexBox项目架构图:驱动层、DOM层、渲染层三层结构
核心流程
MTFlexBox核心渲染流程图:异步解析、缓存、Layout计算
优化思路
树拍平(Litho)、任务异步线程预热、缓存。
相关资料
https://tech.meituan.com/2019/09/19/litho-practice-in-dynamic-program-mtflexbox.html

2.2 DynamicX

渲染流程

DynamicX渲染流程图:协议二进制解析、属性转换、原生控件渲染

协议二进制 在服务端编译期就将 XML 文件解析成二进制,将生成抽象语法树的过程前置到编译期执行,端上执行时,仅需要拿到二进制文件进行属性解析,对于静态值类型,在编译期就直接转换成了对应的数据类型,减少了端上的拆装箱开销;

事件链 实现逻辑动态性。原生提供注册一些原则能力,使用 JSON 对这些原子能力进行编排。

2.3 GaiaX

GaiaX跨端模板引擎架构图:Layout、CSS、Data、JS四协议分层

  • 协议完整: 描述 View 层级关系使用 layout 文件、描述 UI 样式使用 css 、对数据格式进行描述的 data,还有描述逻辑动态性的 js 脚本。
  • 原生渲染:使用 Rust 实现的 Strech 库做双端磨平。(https://github.com/vislyhq/stretch)
  • 表达计算:C/C++ 实现双端共用。
  • 工具链:有 Gaia Studio 作为 IDE。
  • 逻辑动态:引入了 JS 脚本。

2.4 Cube

Cube卡片技术栈架构图:JSEngine、CardEngine、RenderEngine、Platform四层

JSEngine 主要负责卡片 js 逻辑执行和卡片数据变化监听,从而支持开发者在卡片内部写一些业务逻辑能力实现卡片内容和样式的动态变化。

因为卡片场景对性能要求较高,综合包大小和性能等方面考虑,我们选择了 quickjs 作为我们的 js 基础引擎库,同时实现了一个非常小的 js 响应式框架(JSFM),用来支持卡片内的逻辑代码能力。

CardEngine 主要负责卡片数据的解析和绑定、卡片逻辑渲染、构建 DOM 指令、JSAPI 管理、JSBinding、Native 事件通信等。卡片 DOM 树的初始化构建过程,我们并没有把它放在 js 运行时,而是在卡片实例初始化链路中直接通过 C进行指令生成和树构建,一方面是为了保持 js 框架更小更快,另一方面 C 的运行效率更高。

RenderEngine 后端渲染底座,负责卡片布局计算、样式解析、Layer 计算、自绘制组件、同层渲染、光栅化上屏等过程,以及手势、动效等交互效果。

Platform 平台相关接口,包括原子 view 封装、Canvas API、三方组件扩展协议、动画 api 等。

2.5 NativeDSL 小结

  • NativeDSL 方案在卡片级,有动态化诉求的场景十分有效。渲染管线是平台渲染,本身具备“首屏支出特性”。
  • UI 动态性通过 Layout Schema 保证,逻辑动态性需要借住更为强大的语言级别的描述。这本身会牺牲性能。
  • DX 用事件链;GX 用 JS。MTFlexBox 的定位上觉得不适合用,本身不支持逻辑动态性。
  • 渲染管线(解析、测量、布局) 异步;自绘 (Text )补充;列表等容器针对性优化;
  • 对于页面级别的场景,往往伴随着比较复杂的交互,使用 NativeDSL 会有很大调整。

3 KMP

基于 KMP 和 Compose 跨端和动态化方向最近几年也有发展。

3.1 RedWood

RedWood 是 CashApp 开源的基于 KMP 和 CMP 技术的 SDK。 RedWood 可以使用 Kotlin 语言来构建响应式的跨平台 UI。

3.3.1 Compose 为什么可以跨平台

Jetpack Compose(https://developer.android.com/compose)是适用于 Android 平台的现代声明式 UI 系统。摒弃了长期依赖 Android View 系统命令式 UI。

Jetpack Compose技术分层架构图:Compiler、Runtime、UI、Foundation、Material五层

  • Compose Compiler:Kotlin 编译器插件,负责对 Composable 函数的静态检查以及代码生成等。
  • Compose Runtime:负责 Composable 函数的状态管理,以及执行后的渲染树生成和更新
  • Compose UI: 基于渲染树进行 UI 的布局、绘制等 UI 渲染工作
  • Compose Foundation: 提供用于布局的基础 Composable 组件,例如 ColumnRow 等。
  • Compose Material:提供上层的面向 Material 设计风格的 Composable 组件。

各层的职责明确,其中 Compose Compiler 和 Runtime 是支撑整个声明式 UI 运转的基石。

Compose Compiler代码生成与Runtime执行流程图:Composable函数到Slot Table状态树

Compose Compiler 把 基于 @Composable 函数生成代码交付给 Compose Runtime 执行。Compose Runtime 执行生成的这些代码时会生成一个运行时的数据结构 Slot Table,该数据结构是一个线性的数据结构,该数据结构其实就是 UI 状态树 ,状态驱动真正的 Compose UI 渲染树。

RedWood跨平台原理图:状态树到各平台渲染树映射机制
得益于 Compose 的分层,Compose Compiler 编译器和 Compose Runtime 是平台无关的,只需要桥接【状态树转渲染树】这一层就可以实现 UI 的跨平台,同时能够享受到 Compose 声明式 UI、完善的开发套件以及智能重组机制。这部分的原理可以看这个(https://juejin.cn/post/7176437908935540797)

3.3.2 还能动态化

更进一步,KMP 可以把我们的 Compse 代码编译成 JS 代码,运行在 JS 引擎上,渲染系统采用平台 Native 的渲染系统,当我们 UI 需要变更时可以直接下发 JS 实现动态化。

以上是 RedWoods 核心原理。更多细节可参考:

3.2 Kuikly

腾讯今年(2025 年)开源了 Kuikly,同样也是基于 KMP 能够实现跨端和动态化。Kuikly 起步较早有一套自研的基于 Kotlin DSL。

3.3 KMP 小结

先说说好的方面,毫无疑问 CMP 和 KMP 是跨端动态化一个技术发力的方向,依托

  • 现代化的开发方式,声明式+响应式。
  • 成熟的 Kotlin 基建和工具链
  • 对客户端开发优化,使用 Kotlin 语言。

可能有困难的方向

  • 性能问题 该类方案对于 Android 平台来说,可以直接下发平台产物使用成熟的动态化技术(插件化)性能不是问题,但是到 iOS 平台还是要回到执行 JS 的老路,对其性能还是存疑的。

4 自渲染

绘制、手势事件、多机型多平台兼容适配、调试监控等一系列周边配套工具。

  • Futter :渲染 手势事件 多机型多平台兼容适配 调试监控等一系列周边配套工具 ,Framework 级别的。

  • **北海:使用前端技术栈 + Flutter 渲染管线。https://github.com/openkraken/kraken

  • Cube/DX : 自渲染

5 HyBrid 方案

  • **sonic:**webview 容器多进程预热;H5 资源复用;http 原生接管(动态缓存、增量更新、并行加载)…。https://github.com/Tencent/VasSonic
  • uni-app:webview 为容器,开发语言纯粹的前端技术栈。

6 总结

  • 协议二进制;
  • 执行构建 -> 指令构建 -> 解析构建( ssr );
  • DOM 树差量更新、剪枝、拍平;
  • 预载缓存、并发、线程模型优化;
  • 自绘补充;

7 小结

  • 动态化跨端上手容易精深难。
  • 深入渲染性能优化、工具建设、体系化方法论,看过与写过体感区别很大。
  • 涉及技术栈多,JS/TS、Android/iOS、C/C++、JS Engine、Render Engine。
  • 业内成熟方案多,学习资料丰富。

参考

DX

基于优酷业务特色的跨平台技术 | GaiaX 开源解读

跨端动态化模板引擎详解,看完你也能写一个 | GaiaX 开源解读

给 Stretch(Rust 编写的 Flexbox 布局引擎)新增特性,我头都秃了… | GaiaX 开源解读
作为逻辑动态化的基础,GaiaX 表达式是如何设计的? | GaiaX 开源解读

GX

淘宝 Native 研发模式的演进与思考 | DX 研发模式

列表容器&事件链如何助力业务快速迭代 | DX 研发模式

如何持续突破性能表现?DX 性能优化策略详解

从 0 到 1,IDE 如何提升端侧研发效率?| DX 研发模式

Cube

Cube 技术解读 1 | 支付宝新一代动态化技术架构与选型综述

Cube 技术解读 2 | 详解「支付宝」全新的卡片技术栈

Cube 技术解读 3 | Cube 小程序技术详解

Cube 技术解读 4 | Cube 渲染设计的前世今生

MTFlexbox

Litho 在美团动态化方案 MTFlexbox 中的实践

【基本功】Litho 的使用及原理剖析