腾讯开源动态化框架 MXFlutter 的探索及应用
如果无法正常显示,请先停止浏览器的去广告插件。
1. 腾讯开源动态化框架 MXFlutter
的探索及应用
刘浪
腾讯高级工程师
2. •
Content Title 1
3. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
4. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
5. 移动端开发面临的问题
多端开发
动态能力弱
问题
人力成本高
需求迭代慢
6. 跨端技术选型
跨端一致性
研发效率
动态化
高性能
7. 跨端技术的演进
Weex
Flutter
Web React Native Web 技术 React Vue Dart
开发人力少 开发人力少 开发人力少 开发人力少
功能受限 框架较重 框架较轻 框架较重
开发迭代慢 开发迭代快 开发迭代快 开发迭代慢
Webkit 渲染 Native 渲染 Native 渲染 自渲染
8. Flutter 的广泛应用
Native 级别的性能体验、高效的开发方式及丰富精美的 Widget 等特点,在业内得到了广泛应用
9. 问题
AOT 模式下
不支持动态化
+
1. 业务需求快速迭代
2. AB实验
3. 线上问题修复
实现 Flutter 动态化
10. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
11. 初步印象
12. 框架选型
2019年业界 Flutter 动态化方案
业界动态化方式
模版方案
UI DSL 解析器
JS 方案
代表方案
阿里:解析 AST 模版
美团:XML+CSS
淘宝 Kraken
1. 思路:既能写逻辑,又易上手
2. 性能:尽可能的高性能
技术特点
以 XML,JSON 作为 DSL 描述 UI
终端实现 DSL 解析器,将 DSL 还原成 Flutter UI
运行在嵌入式设备,使用Flutter 渲染接口 GCanvas API
动态化文件 开发方式
XML/JSON 编辑模版
Dart 解析为模版
JS 前端技术栈
App 框架开发
上层使用 JS 语言开发,底层使用 Flutter 渲染
13. UI 语法和框架如何选择?
Flutter Like Widget
Vue/React
1. 可以完整对接前端生态
2. 需要自己做布局
3. 进行一层映射转换
1. 需开发一个 UI 框架
2. 使用 Widget 树形语法,无
需转换,简化框架设计
3. 与 Flutter 类似的 API,易
上手
4. 保留了对接 dart2js 的能力
14. 框架设计
1. 采用 Flutter Widget Like 语法,实现 JS Widget
2. JS UI Framework 借鉴 Flutter 和 React,实现 JS Widget Tree 的响应式框架
3. JS 层通过 Channel/FFI 与 MX Dart UI Engine 通信
4. MX Dart UI Engine 直接对接 Flutter Widget 层,实现刷新渲染
JSC
AppCode JS
③ Native层
Virtual Dom
① MXFlutter JS UI Framework
DSL
② MXFlutter UI Engine(AOT)
通道
Flutter
Widget Tree
Flutter(AOT)
JSVM
15. 如何支持 Widget 组装语法?
1. JS UI Framework 提供 Widget 类定义,并支持 toDSL 能力
2. MX Dart UI Engine 提供通过 DSL 创建 Flutter Widget 的能力,并支持构造方法的参数
ListView 的 JS 定义
业务 ListView 的使用
创建 ListView 符号映射。支
持通过 JSON 创建 ListView
16. 支持局部刷新,状态保持
1. 通过支持嵌套子 StatefulWidget 的局部刷新,减少 DSL 数据量。
2. 在 JS 层对控制节点生成 Element Tree,使用 ElementPath( NodePath-ClassType-Key ) 存储当
前状态,实现状态保持。
局部刷新
状态保持
17. 关于 JS<->Dart 的跨语言调用
几个关键点
1. 框架设计:异步框架,一次页面显示,只有一次必要的跨语言交互,绘制过程无交互
2. FFI 通道,保证传输速度
3. 统一 UTF16 编解码,使用 Uint16List 作为数据传输格式
JS
JS Thread
Int
String
Map
类型
编码
ByteData
FFI C
API
iOS/
Android
ByteData
类型
解码
Dart
Flutter UI Thread
18. 引入 TypeScript
重写 JS Framework
原有 JS UI Framework
全部用 TS 重写
widget 自动生成 npm 管理
自研 MXJSBuilder 工具,
一键生成 1400+ Widget,
对齐 Flutter 引入 npm 管理,接入前
端生态。使用 lerna,一
键编译成目标 bundle
文件。
19. 如何生成1400个 TS/Dart Widget?
方案1:Dart-lang Analyzer,小巧简单
TS: Widget 定义
Dart Source
File CompilationUnit AST Tree
字符串拼接
Dart:Widget 符号映射
问题:
1. AST 缺少完整的类型继承及符号引用关系
2. 字符串拼接,扩展性较差
方案2:定制 dart2js 编译器
20. dartdevc 和 dart2js
dartdevc:开发环境。代码可读性较强,但文件太大,调试信息多
dart2js:生产环境。经过多轮优化,代码不可读,但执行更高效
dartdevc 编译
dart2js 编译
21. dartdevc 编译流程
dartdevc
JS AST
Dart
KBC
Dart AST
CFE
DevJS
Dart2JSProgramCompiler
Kernel byte
code
Common Front End
Common Front End
Optimizer
dart2js
Dart
Common Front End
Dart AST
KBC
Kernel byte
code
Control Flow Graph
JS Back End
SSA
CFG
CFE
JS Printer
Static Single-Assignment
Program Close Word
tree-shake and create close world
对 dartdevc 模式,按照正确方式组装 JS AST,就能生
成可读的 JS 代码
问题:dartdevc 编译器生成的代码风格和手写风格差异很大
JS AST
JS Printer
IL Node
JS
Dart2JSProgramCompiler
22. 绑定 JS-Dart AST 生成 Widget
Dart2JSProgramCompiler
Dart
CFE
JS AST
JS Printer
Dart AST
Dart2JSProgramCompiler
Common Front End
Widget 符号映射
问题:JS AST 上已经擦除了类型信息, TS Widget 如何生成?
解决方案:通过绑定 JS AST 和 Dart AST, 获取相关类型信息,生成正确的 TS Widget
JS 的代码结构和语法
JS AST
+
Dart AST
js printer
补充类型及继承链信息
开发 AST To Mirror Printer,生成 Dart 侧 Widget 符号映射表
TS Widget
DevJS
23. 演示效果
24. 框架总览
TS UI Framework
1.
2.
3.
4.
5.
轻量响应式 UI 框架
1400+ TS Widget
与 Flutter 相同的 API
接入 TS 语言,可以使用 npm 生态
便利的 cli 工具
App Code(TS/JS)
MXFlutter UI Framewrok(TS)
Widget
Flutter UI Engine
1.
2.
3.
4.
1400个 Widget 支撑 DSL 解析
UI刷新逻辑支持
事件相应支持
Flutter API支持
Native 层
1. FFI 打通 JS<->Dart 双向高速通道
2. JSVM 管理 JSCore/V8
3. JS 资源管理,js common modle require 支持
工具链
1. 自动生成1400个 Widget 定义和符号映射
2. iOS Safari/Android Chrome 的调试
BuildEngine
Event
JSAPI
MXFlutter Flutter UI Engine(Dart)
WidgetProxy
BuildEngine
Event
JSAPI
Widgets
Flutter
Framework
(Dart)
Rendering
Animation
Painting
Gestures
Foundation
Flutter Engine
(C++)
Animation
Dart
Text
25. 如何开始?
1. 安装 mxflutter cli 程序
2. 新建模板工程
3. 一键生成 JS Bundle
26. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
27. Dart 代码动态化
前端开发模式,对接前端
生态
+
MXFlutter
框架
终端开发模式,对接现有
Flutter 生态
Flutter 动态化
28. 三个要素
编译:将业务 Flutter 代码编译成 JS
转换:支持 JS Widget,转成 DSL,生成 Flutter
Widget
能力:事件响应及刷新
29. 初步方案
App Code (Dart)
dart2js 编译器
App Code (编译生成的JS)
Dart JS Runtime
MXFlutter JS Framework(标准JS)
MXFlutter UI Engine(Dart)
Flutter Engine
Dart SDK
30. 问题
编译 JS 并不是简单语法转换,使得编译 JS 与标准 JS 交互困难
1. 因数据类型不兼容,需要很多定制代码
2. MX JS UI Framework 支撑两套 JS(编译/手写) 运行,维护困难
3. Flutter 版本升级难度大
Dart
JS
var array = ["a","b",18];
var jsObj = {"a":"av","b":"bv"};
let array = JSArrayOfObjectL().of(["a", "b", 18]);
let jsObj = new (IdentityMapOfStringL$StringL()).from(["a", "av", "b", "bv"]);
Dart var x = obj.bar; NoSuchMethod exception
JS var x= obj.bar; undefined value
31. 新方案
App Code (Dart)
App Code (Dart)
MXFlutter Dart Framework
MXJSComplier
MXJSComplier
App Code (编译生成的JS)
Dart JS Runtime App Code (JS)+ MXFrmework(JS)
MXFlutter JS Framework(标准JS) Dart JS Runtime
MXFlutter UI Engine(Dart) MXFlutter UI Engine(Dart)
Flutter Engine
Dart SDK
Flutter Engine
Dart SDK
32. 编译器定制相关能力
MXJSCompiler
MXFlutter App JS Bundle
Flutter App
1. 支持生成 JS 代码和 Api 代理
App Code (Dart)
Flutter
Framework(Dart)
Framework
Widget
IO/Platform
DartSDK (Dart)
2. 替换成 MX 渲染逻辑,删除不用的代码
3. 增加toDSL 能力,删除不用代码
4. 对 Platform 的调用转调到 JS Adapter
JS Rumtime
Flutter Engine
DartVM
App Code (JS)
Framework
Widget
Flutter
Framework(JS)
IO/Platform
DartSDK (JS)
JS Rumtime
5. API:同时生成符号映射(json->invoke)
6. 调试:sourcemap 生成支持 JS 调试
Dart 代码
MXFlutter UI Engine
Flutter Engine
DartVM
33. 编译器改造方案
方案一
dart2js
Common Front End
Optimizer
CFG
Dart
CFE
Common Front End
Dart AST
KBC
Control Flow Graph
JS Back End
SSA
Static Single-
Assignment
Program Close Word
Kernel byte code
JS AST
IL Node
JS Printer
Dart2JSProgramCompiler
tree-shake and create close world
方案二
方案1:修改 JS Back End,编辑 JS AST/Printer
简单高效,所见即所得。但在 dart2js 中,JS Back End 的输入是经过多轮优化的 IL Node,逻辑易受前面链路的影响
方案2:转换 Dart AST,在 Front End 后串联 MX 转换层
符合编译器[编译前端]->[转换]->[优化]->[编译后端]模块化设计
JS
34. 定制 Common Front End
dart2js
Dart
词法分析
语法分析
语义分析
BuildBody
BuildOutlin
e
MXASTTransform
MXDart AST
把 AST Transfonm 放到 CFE 的
BuildASTBody 后,并定制 Constant
Evaluator
AST
Constant
Evaluator
语法验证
MXCreateEnvironment
1. 第一趟:创建构建 MX 逻辑
的环境
SSA
CFG
AST
Program Close Word
JS Back
End
MXConstantEvaluator
MX AST TransformerMgr
3. 第三趟:根据第二趟对类定义的修改,加入 toDSL 函数
Add MX Logic
Const Value Add
DSLMap
Redirect Add DSLMap
Add Widget toDSL
MXAST
MXConstantEvaluator
4. 定制常量求值
2. 第二趟:AST Transform
35. 编译 Flutter Framework
Framework:替换MX渲染逻辑
MXJSCompiler
同时编译 Patch 文件,替换原逻辑
Flutter
Framework(Dart)
Widget
MXFrameworkPatch
Framework
MXPatch AST
Flutter AST
加入MX逻辑
Tree-shaking
删除不用代码
MXJSFramework
1400+Widget
1. 增加 toDSL 能力
2. 添加 MX 渲染逻辑
3. 删除不用的代码
Flutter ListView
Widget
DDC JS ListView Widget
DSL
ListViewDSL : {
className: ”ListView",
key: {
className: ”Key",
value: ”mainList”},
scrollDirection: {
className: ”ListView",
Value: 1},
};
36. 三步完成工程接入
1.
定义业务入口文件
2、定义配置文件
3、运行可执行文件,生成 JS Bundle
37. 如何选择两种方案呢?
开发特点
TS 方案
dart2js 方案
适用场景
限制
TS 开发,可以使用前端 1. 对 TS 开发较为熟悉 1. 有一定的 TS 学习成本
组件 2. 简单业务场景 2. 开发效率会受一定影响
Dart 开发,复用Flutter 1. 现有存量 Flutter 业务 1. 执行效率有一些损耗
生态 2. 快速迭代的新业务 2. JS Bundle 偏大
38. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
39. 业务落地
40. 接入业务的问题
问题1:复杂页面,需要手动定义较多 JS API 及 符号映射
解决方案:
1. 通过配置文件的声明及自动化工具,自动生成
2. 优化配置文件的定义,精简 API 的声明
41. 接入业务的问题
问题2:定位问题较困难
1. 涉及编译的 JS Bundle、Native、MX Dart UI Engine、MXJSComplier
2、Safari / Chrome 调试 JS 代码
3、日志定位问题
42. 性能数据
线上环境,iPhone 11
43. • 背景
• 基于 JS 的 Flutter 框架的设计
• MXJSComplier 介绍
• 框架的业务落地
• 未来展望
44. MXFlutter Roadmap
https://github.com/tencent/mxflutter
1、dart2js 方向
① 支持更自动的生成第三方库
② 补充更多底层 api 的实现
③ 完善 MXJSComplier 的易用性
2、前端方向
① 全新 Vue/React 前端解决方案
② TS Flutter Like
45. MXFlutter 前端解决方案
46. 腾讯动态化框架 TDF
腾讯动态化框架
Tencent Dynamic Framework
TDF View
生
态
TDF Widget
TencentOffice
Hippy
MXFlutter
小程序
其他领域
+
支
撑
AppCenter Core DevTools
平台 内核 工具
47.
48. 腾讯开源动态化框架_MXFlutter_的探索及应用
扫描二维码 提交议题反馈