Flutter轻量引擎实践
如果无法正常显示,请先停止浏览器的去广告插件。
1. Flutter 轻量引擎实践
字节跳动 Flutter 生态分享
侯华勇
就职于字节跳动 Flutter Infra 团队,主要负
责 Flutter 引擎优化、稳定性建设、以及基
础设施搭建等相关工作。
2. 01 Flutter 多引擎背景介绍
02 Flutter 轻量引擎实现原理
03 轻量引擎相关问题
04 轻量引擎后续进展
3. Flutter 多引擎背景介绍
目前在混合工程中集成 Flutter 业务主要有两种场景,以整⻚方式来进行 Flutter 展示和在一个⻚面中嵌入多个 Flutter Item,我们
通常的处理方式是复用同一个引擎或者创建多个引擎来进行展示。
NativeView
Navigator
FlutterView
FlutterView
NativeView
FlutterView
FlutterView
4. Flutter 轻量引擎实现原理
5. Flutter 轻量引擎实现原理
6. Flutter 轻量引擎实现原理
内存占用
官方数据:双端新增Engine都仅需180KB. https://flutter.dev/docs/development/add-to-app/multiple-flutters
实测Android新增一个Flutter卡片,内存增量~0.8M;iOS新增一个FlutterVC,内存增量~3.8-4.8M(后续可优化至
~500K)
FlutterView数量 2 3 4
Android内存值 68.8 69.6 70.5
iOS内存值 39.3 42.7 47.6
7. Flutter 轻量引擎实现原理
启动速度
Android:速度提升~2.63倍
iOS: 速度提升~9倍
安卓以 FlutterFragment 形式新增卡片,统计为Engine开始创建到 onFlutterUIDisplayed
普通方式创建 EngineGroup创建 Android 耗时 140~150ms 50~60ms Android 耗时
iOS 耗时 280~300ms 30~40ms iOS 耗时
8. 轻量引擎相关问题
• 引擎之间的数据同步
• imageCache共享问题
• ⻚面不可⻅时的内存处理
• FlutterView 自适应宽高
9. 轻量引擎数据同步
由于多引擎是利用 Dart 的 IsolateGroup,相比之前没有 IsolateGroup 的情况,内存和启动速度上都有很大的提升。然而多个引
擎虽然在同一个 IsolateGroup 中,并且使用的是同一个 Heap,但 Isolate 之间的数据仍然是不共享的。
10. 轻量引擎数据同步
使用MethodChannel实现
在业务实现过程中,多个⻚面之间进行数据共享是一个非常常⻅的述求,最普遍的场景就是用户信息,Isolate 之间的数据
是不共享的,通过 MethodChannel 可以在引擎之间进行数据同步达到这个目的,但是使用 MethodChannel 会有一些问题
1、首先需要每一端都要书写相应的 Native 实现;
2、其次是 MethodChannel 在传递数据的过程中会进行序列化,性能会有损耗。
11. 轻量引擎数据同步
Dart 的 Isolate可以通过 Port 的方式进行通信,我们可以借助这项机制来实现多个Isolate之间的数据同步。
• 将需要共享数据收敛到一个 ServiceIsolate 中,这样共享数据还在 Dart 层,不再需要考虑多端的问题;
• 进行更新的时候,发送消息到 ServiceIsolate 中,此时 ServiceIsolate 将更新的消息广播到其他的 Isolate 中;
• 获取最新数据的时候,向 ServiceIsolate 发送一条请求消息,ServiceIsolate 在收到消息之后将数据再发送回来;
• 通过 FFI 进行 Isolate 间 Port 的绑定,可以直接在不同的 Isolate 之间传递 Dart 对象,避免序列化和反序列化。
12. 轻量引擎数据同步
数据同步的使用方式
13. 轻量引擎图片缓存
imageCache 数据之间的共享问题
•
•
图片内存不共享,同一张图片在多个 Engine 中显示需要重复解码,重复占用内存
每个 Engine 默认有 100M 的 ImageCache,如果不共享,可能出现不同引擎利用率差异大的问题
14. 轻量引擎图片缓存
imageCache 数据共享方案
15. 轻量引擎内存销毁
⻚面不可⻅释放内存
官方对外说明额外创建一个卡片引擎内存增量~180K,在实测的过程中 iOS 每多创建一个引擎的内存增量在4-5M。为什么会产生这么大的差异呢
使用 Instrument 获取内存增⻓详情的过程中,从官方的 Demo 中不断的 Push 进入新的轻量引擎界面,可以看到里面内存占用比例最高的部分是在进行渲染
过程中产生的缓冲区,这个所需内存块的大小取决于屏幕分辨率以及创建出 FlutterView 的 ViewportMetrics。
16. 轻量引擎内存销毁
⻚面不可⻅释放内存
使用 Instrument 进行多次 Push 之后的内存占用情况如上图,在下一次 Push 的时候上
一个⻚面内存占用大大降低,使用此方案之后除去当前展示⻚面中的 Surface 占用,每
新增一个⻚面的内存增量由原来的5M,减小到~500K。
17. FlutterView 宽高自适应
轻量级引擎使用方案使 Flutter 可以更方便应用到列表 Item、Banner 等场景中,但是在使用 FlutterView 过
程中由于父布局的限制,Flutter 内容只能充满父布局,无法根据具体的内容进行自适应的布局,这使得该
方案在一些常规场景中有一些问题。
18. FlutterView 宽高自适应
•
•
在获取整个Flutter布局的时候我们需要修改 FlutterView 尺寸变更的通知流程,先给 Dart侧 一个足够大的Size,保证 Dart 在
布局的时候能够测量出正确的结果;
然后在监听 Dart 侧的布局,获取宽高通知给 Native;
19. FlutterView 宽高自适应
如果在⻚面中存在图片,由于 Dart 侧需要多次 Layout 才能获取到准确的宽高值,而在获取到最终的宽高之前,不能修改父布局的尺寸,否则父布局的尺寸
变动会同步到 Dart 侧然后影响到 Dart 侧的布局。
获取到解码 _image 信息之前,测量的逻辑是 ImageWidget 有设置宽高就使用设置的宽高,没有设置宽高就是使用最小值。似乎要求业务方在自适应布局的
场景中指定图片的宽高就可以了,但是真正在代码编写的时候,这个是比较难做到的,而在一些布局中图片的宽度和高度是没法获取的。
最终我们采用要求业务方书写宽高比的方式,结合图片宽高比和 BoxConstraints 中父布局给的限制,可以在没有设置宽高,没有解码数据的情况推测出
ImageWidget 应该占用的占用大小。
20. 轻量引擎后续规划
• 多引擎之间的线程共享导致的性能问题
• 多平台下的轻量引擎适配
• 单个 isolate 中实现多窗口
21. Q&A
22. UME Kits competition
插件开发竞赛活动
UME(flutter_ume) 是一款 Flutter 应用内调试工具平台,支持插件扩展。
Pub:https://pub.dev/packages/flutter_ume
GitHub:https://github.com/bytedance/flutter_ume
本次活动针对 UME 的插件开发展开竞赛,将于杭州 Flutter Festival
(4.9)上正式宣布,更多活动细则我们将在字节跳动 Flutter 技术交流群
中推送,欢迎扫码加入。
字节跳动 Flutter 技术交流