基于 QuickJS、BOM 规范的基于 Flutter 的跨 APP、WEB 的跨端动态渲染机制 — FlutterDOM
简介
跨端框架的分类
目前市面上已经有很多跨端的框架,按照开发规范分类大致有以下分类:
- 自定义的 DSL 规范:如小程序的 wxml、wxss
- 使用特定开发框架规范:如React Native、Flutter
- 使用 WEB 开发规范,如 Hybrid App、WebF
与本专利技术最接近的现有技术为 WebF。该技术使用基于 Flutter实现了自绘渲染引擎(布局引擎、CSS、元素等),并在上层实现了基于原生应用的 JavaScript Engine,在引擎中注入 BOM、DOM 能力,实现了类浏览器的技术架构。
WebF 的实现方式
由于WebF对性能有着较高的要求,且主要输出的产物是苹果与安卓App应用,所以该技术的分层架构设计如图:

- 黄色部分的两个分层是Flutter原有的分层设计,包括底层平台的能力与框架的跨端渲染的能力。其中WebF在框架渲染能力层封装了Web API相关实现
- 绿色分层是WebF拓展的逻辑运行能力层,主要用于用于JS代码的执行。包括原生JS运行时和对框架渲染能力层的Web API实现的封装。
- 总之,Flutter的底层平台能力是同时跨端渲染机制是支持跨端的,但是WebF只实现了原生端的逻辑运行能力而忽略了浏览器端的逻辑运行能力与渲染能力。
FlutterDOM 的设计与实现
FlutterDOM致力于实现一个跨原生APP、WEB的一个跨端渲染方案,充分利用 Flutter 跨Native、Web的渲染能力。主要点有两个:
- 补全浏览器内逻辑运行能力(分层架构图右上角),并提供统一的JS运行时环境来运行JS代码。
- 使用JS语言重新封装WebAPI实现,剥离该功能对原生运行时的依赖,使之能实现一份代码同时对接原生逻辑运行能力以及浏览器内逻辑能力。
带来的好处:
主要是可以在多端一致性上有更好的体现,在WEB浏览器中也会有一个较为纯净的与APP端相同的渲染能力。在实现跨端APP低代码编辑器B端预览场景上会有优势,比如可以在浏览器中模拟APP渲染的逻辑。
实现的方式:
- 首先抽离出JS运行时库来统一调用规范,具体包括JS运行环境初始化、JS代码执行、相互通信的能力等。其中原生JS运行时选择使用Dart第三方库(flutter_qjs)进行封装,浏览器内则使用NPM第三方库进行封装(quickjs-emscripten)。通过以上方式则抽象并替换了WebF的原生JS运行时能力,顺带解决了跨端一致性的问题。
- 重新封装WebAPI的实现的原因是WebF的WebAPI的实现与原生能力(C语言)绑定过深,导致无法在浏览器的JS运行环境中使用,所以重新封装的主要实现技术栈改为了JS实现,达到了一份WebAPI代码在多端JS运行时中运行的目的。
分层设计
- 黄色部分的两个分层是Flutter原有的分层设计,包括底层平台的能力与框架的跨端渲染的能力。其中蓝色的方块是FlutterDOM在框架渲染能力层拓展封装了Web API相关实现,来支持多种JS运行时。
- 绿色分层是WebF拓展的逻辑运行能力层,其中蓝色方块不仅重新封装了原生JS运行时,添加了新的浏览器JS运行时设计,并且使用JS语言重新实现了Web API的上层封装。
- 总之,FlutterDOM 在保留了分层的情况下,先在右上角补全了浏览器JS运行时的能力,后拓展了Web API的跨端实现与封装。充分利用了Flutter的底层平台能力实现了跨端渲染。

FlutterDOM 渲染流程步骤

1. 加载 FlutterDom 组件
Flutter项目在项目运行的时候加载并渲染FlutterDOM组件,需要传入JS入口代码、自定义JS事件处理逻辑、渲染窗口大小、背景色、是否开启调试模式、设置HTTP请求拦截器等参数。FlutterDOM组件接受到参数之后会进行执行渲染逻辑:
- 初始化创建FlutterDom总控制器用于管理当前组件相关的生命周期以及页面池
- 渲染的方法会创建并返回一个特定的 RenderObject 类型来实现布局和绘制逻辑,该方法会调用FlutterDom总控制器的视图创建方法来进行创建(这里会进入到第二步)。
- 实现RenderObject的视图大小更新逻辑。
2. 初始化创建FlutterDom总控制器、模块控制器
在FlutterDOM组件的渲染实现里需要透传JS入口代码、自定义JS事件处理逻辑、背景色、来创建FlutterDom总控制器,执行以下核心步骤:
- 注册JS回调Dart的事件处理方法,监听JS代码中的自定义事件的抛出,执行Flutter项目传入FlutterDom的JS自定义事件处理回调参数。
- 添加当前JS入口文件到历史记录中,实现历史记录路由逻辑。
- 初始化创建FlutterDom视图控制器来进行视图操作(这里会进入到第三步)。
- 创建并注册模块控制器,包括且不限于接口请求、通信封装、跳转封装、历史记录路由、异步存储等模块功能。
3. 初始化创建FlutterDom视图控制器
FlutterDom视图控制器包括核心的视图渲染逻辑,核心步骤如下:
- 创建新的JS页面并添加到页面池中,初始化JS运行时并注入Web API。
- 添加Flutter应用监听逻辑,监听事件并触发对应的渲染逻辑,如语言更改事件、布局更改事件、内存压力过高事件等。
- 统一注入Dart方法给JS运行时调用,包括FlutterDom总控制器创建的模块执行能力,以及定时器、帧渲染器、日志能力等。
- 注入内置HTML元素创建逻辑,并自动自动创建Document、Window根节点。该能力会暴露给JS运行时,允许JS代码在运行时内创建或更新元素。
- 等待创建完成之后执行调试模式逻辑以及开始执行JS入口代码。(第四步)
4. 执行JS入口代码
在JS入口代码中包括DOM的一些操作逻辑,注册用户操作事件的监听逻辑,异步逻辑等,在初始化的时候会进行初始化节点创建与更新逻辑,此时会触发画布刷新(第五步)。
5. RenderObject触发画布更新
画布更新逻辑如下:
- 在JS代码进行画布节点更改,触发画布更新逻辑,发送UI指令到FlutterDom视图控制器。
- FlutterDom视图控制器会根据指令进行元素的创建、更新、插入逻辑,后触发Flutter视图的更新。
- 视图更新渲染的时候会获取RenderObject对象,此时会根据最新的根节点重新生成,后完成画布的更新。
6. 等待用户操作画布,或JS异步更改画布,再次触发画布更新
与第四步类似,在等待用户操作了画布,JS异步逻辑对节点发生了更改后,再次出发画布刷新(第五步)。