「全网首发」Flutter element embedding 初探(面向 Web 未来)
本文可能是全网首篇探索 2023 Flutter Forward 中关于Flutter element embedding的文章。
前沿
(是的,没写错,不是“前言”,只因看到这篇文章的你已经走近技术的最前沿了 ~)
Flutter element embedding 是什么?
简单的说,就是把 Flutter 代码当做一个<div>
嵌入到 Web 页面中,且可以相互操作。
在这之前,Flutter for Web 想嵌入到 Web 页面中,就只能通过<iframe>
的方式嵌入,这个笔者在以前也是尝试过多种奇淫巧技,想让 Vue 代码与 Flutter for Web 页面深度融合,但都不切实际。笔者最后就完全去使用 Flutter 布局实现(Flutter Web - 优雅的兼容 Flutter App 代码)。
为什么说它可能是 Web 的未来?
- 现在流行的各类前端 UI 组件库(Ant、Vant 等等),都是被现代前端框架(Vue、React)限制住的,而字节的 semi 虽然是超脱于框架本身,但其实还是被前端语言束缚的。虽然说前端基本可以一统天下,但想进一步在桌面/移动终端提高渲染能力时,能选择的方案就很有限。
这里额外解释下:
比如 RN、weex 等混合渲染方案,但这些方案本身是很难支持纯前端的,演进上就会变成 RN for Web,但这其实不符合前端趋势的。
那如同 uni-app 这种封装全家桶方案,问题是很多,但它在发展上完全可以用 Flutter element embedding 来面向未来(可能换车道也很难)。
- Flutter 在 Web 上也是 Skia 渲染的,在复杂场景或者动画下,比 Dom 布局性能上更好,更强大(特别是针对动辄上千个 Dom 标签的页面)。
那它在未来上,完全是可以代替各类 UI 组件库,形成全端共用的组件库。any where any use 。
摸索
只能有“摸索”这个词汇,因为是未来的能力,网上的资料只有大会上的宣讲视频,没有官方文档,没有源码解释,甚至官方 Demo 的地址都没有放出来。好在熟悉 Flutter 的套路,最终在 Samples 中里面找到了示例源码(源码传送门)。
分析产物
官方示例地址:flutter-forward-demos.web.app (网络加载慢显示不出来的话,需要翻🧱)
如上图所示,官方 Demo 整体是一个 Web 页面,动画效果和双边相互操作上都极为惊艳,The Future is Coming!
我们打开 Chrome 调试工具,可以看到:
Flutter 就是加载在flutter_target
这个<div>
上,已经完美的能与 Web 结合在一起了!
再来看看产物大小,这个也是决定这个方案的适用面:
可以看出最大的文件是canvaskit.wasm
2.6M,这个是 webassembly 类型的 Skia 渲染文件,虽然大,但可以看出它是通用的,所以说只需要下载一次即可。甚至笔者觉得未来可能会融入到浏览器标准里。

Flutter 的执行文件还是我们的老朋友main.dart.js
占用 475KB,不能说小,但确实是在可接受范围内的,毕竟 Flutter for Web 还是有分包手段的。
使用 canvaskit 的方式也会带来字体加载的成本,这个后续再研究,毕竟现在商用的 Flutter for web 都是flutter build web
来打包 Web 模式,使用系统字体即可,所以极少有人关心字体加载问题(canvaskit 模式需要给引擎指定字体文件)。
尝试运行
(这个步骤花功夫最多的还是在找源码地址上 - -|||)
源码传送门 可以看到,它连个 README 都没写 ...
下载源码后,是运行不了的,因为大家的 Flutter 版本不够超前,需要切换到试验性版本。
这里就额外安利一个工具:fvm flutter 版本管理器 ,不然来回切换 Flutter 版本就变成一个痛苦的开始。
这工具十分好用,在正确安装后,首先我们执行:
fvm releases
它会列出所有的 Flutter 版本

我们需要安装的就是 beta 版本的 3.8.0 以上的版本
fvm install 3.8.0-10.1.pre
执行安装命令,等待安装完成。
执行
fvm list
可以查看我们装过的版本

这之后,在项目里执行
fvm use
选择当前项目需要的版本(这不会影响其他项目使用)。

然后就可以愉快的 pub get 了,但要注意一点,都需要在命令前增加 fvm
fvm flutter pub get
fvm flutter run -d chrome
这样,我们就把官方示例源码跑起来了。
源码解析
加载入口
首先我们要关心是如何把 Flutter 加载到 Web <div>
上去的。
是在 web/index.html 中
与之前的实现不同,是通过 document.querySelector("#flutter_target")
获取到 Dom 对象,再在引擎初始化中指定 hostElement
即可完成加载绑定。
笔者疑惑:
如果一个页面只能加载一个 Flutter
<Div>
,那这个方案实用性就不大了。可能是 Demo 本身只是为了演示 embedding 的能力,所以没有实现,或者还在开发过程中? 按笔者想法,这能力应该要复合 Flutter 多引擎,提供多个
runApp()
入口来绑定是最为合理的。
代码解析
Demo 工程代码很简单,也很惊艳,如大会所说的,JS 这库算是颠覆性设计了。
lib/main.dart
只要增加 @js.JSExport()
注解,能直接把 Flutter 属性/方法开发给 JS 调用
web/js/demo-js-interop.js
这个 appState
是什么?我们可以通过控制台打印看一下:
看出所有的方法都已经注册在 window._appState
上,这个又是怎么实现的呢?
lib/main.dart
关键就是在初始化的时候,用 js_util
做了绑定。
addHandler()
也同理,只不过注册的是一个回调方法来实现的。
至此,JS 与 Flutter 相互操作就已经理解明白了。
还有一点比较惊艳的,就是可以控制 CSS 属性来改变 flutter 代码样式,如示例中的那样,可以翻转,倒影等等。
当然是 Flutter 整体改变的方式,如果要改变 Flutter 中某一个组件的样式,可能还是要通过 JS 交互来做。
这个代码也十分简单,比如倒影:
先增加样式文件
css/style.css
按钮触发 class
切换即可 ~
web/js/demo-css-fx.js
后续
本文只是对 Flutter element embedding 能力初探,按 Flutter 的套路,这能力应该在今年 4月 Flutter 4+ 的版本上就会体现出来,所以大家可以兴奋的搓搓手了。
对于笔者来说,它出现的意义更为重大,不仅当下工作上有一个 Web UI 组件库选型的问题,而且可以无代价的 Flutter 多引擎组件库支持成 Web UI 组件库(快捷传送门:从零开始|构建 Flutter 多引擎渲染组件)。
这条路的坑坑洼洼少不了,目前要解决的问题也很多,需要怀着坚定的决心往前踩才行 ~
题外话,本来想每篇文章都继续坚守 iOS 阵地的,但本篇确实只有 Web + Flutter,所以发到前端 ~~
感谢阅读,如果对你有用请点个赞 ❤️

转载自:https://juejin.cn/post/7203571284558331965