Flutter简介
它Google推出的跨平台语言,同时支持
android
,iOS
和windows
,使用skia图形渲染引擎,渲染效率可达60FPS以上。
Flutter框架
如下图,它主要分为以下三层
- Framework: 采用纯dart编写,主要负责界面构建,手势,布局,基础服务的包装和提供,围绕着Widget树,Element树,Render树的构建和管理而展开的
- Engine,提供了dartvm服务器,dart运行的隔离空间,文本渲染,图形渲染,跨平台接口
- Embedder: 类似于Native的容器层,用于初始化Flutter engine,为其提供运行及环境和资源,如渲染组建的设置,线程的设置,其他资源文件的初始化
Flutter Engine
在engine中可以看到flutter engine的完整源代码,它的工程根目录主要结构如下
├── common
│ ├── settings.h
│ └── task_runners.h
├── flow
│ ├── embedded_views.h
│ ├── layers ...
├── flutter_frontend_server
├── fml ...
│ ├── command_line.h
│ ├── message_loop.h
│ ├── native_library.h
│ ├── task_runner.h
│ ├── thread.h ...
├── lib
│ ├── io
│ ├── snapshot
│ ├── ui ..
├── runtime
│ ├── dart_vm.h
│ ├── runtime_controller.h
│ ├── runtime_delegate.h
│ ├── service_protocol.h ...
├── shell
│ ├── BUILD.gn
│ ├── common ..
│ ├── platform/android
│ ├── platform/darwin
│ ├── platform/embedder
│ ├── profiling
│ ├── testing/observatory
│ └── version
├── sky ..
├── third_party
│ ├── tonic
│ └── txt
├── tools ..
├── vulkan ..
└── web_sdk ...
- common: flutter构建,dartvm的一些基本的常量
- flow: 图层的组装流程
- flutter_frontend_server: 编译dart原代码,转换成dart内核的可执行文件(.dill)
- fml: 主要是协调管理TaskRunner和MessageLoop的事件
- lib: 对外提供了flutter framework的接口(window)
- runtime: 提供了dartvm,处理跨平台的消息
- shell: 实现了跨平台的embedder层的对接
Flutter与线程
以iOS为例子,在启动FlutterApp的时候会有iOS端的Embedder层FlutterEngine
初始化Shell,并提供它所需要的线程资源,platform的初始化信息绑定
@implementation FlutterEngine {
fml::scoped_nsobject<FlutterDartProject> _dartProject;
flutter::ThreadHost _threadHost;
//Shell实例,初始化embedd时用
std::unique_ptr<flutter::Shell> _shell;
//engine的标示
NSString* _labelPrefix;
//内置的methodChannels
fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
fml::scoped_nsobject<FlutterTextInputPlugin> _textInputPlugin;
fml::scoped_nsobject<FlutterMethodChannel> _localizationChannel;
fml::scoped_nsobject<FlutterMethodChannel> _navigationChannel;
fml::scoped_nsobject<FlutterMethodChannel> _platformChannel;
fml::scoped_nsobject<FlutterMethodChannel> _platformViewsChannel;
fml::scoped_nsobject<FlutterMethodChannel> _textInputChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _lifecycleChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _systemChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _settingsChannel;
//默认的消息信事,用来和RuntimeController通信传递消息
FlutterBinaryMessengerRelay* _binaryMessenger;
....
//执行flutter main
runWithEntrypoint ...
//创建Shell并初始化
- (BOOL)createShell:(NSString*)entrypoint
libraryURI:(NSString*)libraryURI
initialRoute:(NSString*)initialRoute {
//只运行创建Shell一次
if (_shell != nullptr) { return NO; } ...
// 设置当前的线程为PlatformThread,Flutter推荐是在主线程初始化引擎,所以这里对应的就是主线程
fml::MessageLoop::EnsureInitializedForCurrentThread();
uint32_t threadHostType = flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::GPU |
flutter::ThreadHost::Type::IO;
bool profilerEnabled = false;
#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
(FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
profilerEnabled = true;
#endif
if (profilerEnabled) {
threadHostType = threadHostType | flutter::ThreadHost::Type::Profiler;
}
_threadHost = {threadLabel.UTF8String, // label
threadHostType};
...
//配置4个runner对应的线程
flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
_threadHost.raster_thread->GetTaskRunner(), // raster
_threadHost.ui_thread->GetTaskRunner(), // ui
_threadHost.io_thread->GetTaskRunner() // io
);
//创建shell,绑定TaskRunners,platformData,settings,on_create_platform_view,on_create_rasterizer
_shell = flutter::Shell::Create(std::move(task_runners),
std::move(platformData),
std::move(settings), // settings
on_create_platform_view,
on_create_rasterizer
);
...
通过上面代码可以看出FlutterEngine的线程创建和管理由Native端负责提供,各自平台的Embedder提供了4个Task Runner,每个Task Runner负责不同的任务.
- Platform Task Runner: 在初始化Engine的时候,它会将当前线程设置为
PlatformTaskRunner
的线程, 它是与Native交互的的桥梁,官方要求所有与native的交互都必须要在PlatformTask,这是因为flutter没有多线概念,为了防止资源竞争和不可预知的错误 - UI Task Runner: 它是flutter engine的核心,主要负责dart端main函数代码的执行,所有的widget树,element树,render树的构建,以及所有运行在mainIsolate下的任务.
- IO Task Runner: 负责比较费时的I/O操作,主要是针对图片的读取和解码操作,避免阻塞其他的TaskRunner,如Platfom Task Runner对应的是Native的主线程,阻塞时间过长会导致WatchDog超时,被系统强制杀掉。
- GPU Task Runner: 对应的是Raste线程,执行GPU的绘制任务,将来自UI Task Runner处理好的RenderObject树(图层树),进行光栅化操作,转化为pixel buffer,提交给GPU执行。
Flutter构建模式
- Debug: 调试模式
- 在这个模式下,支持assert断言
- 可以通过
Observatory
分析和调试代码,比如方法的调用次数,总时间话费 - 支持
JIT
(Just in time)模式,通过hot reload
,快速的的将中间产物代码提交给dart vm执行.
- Release: 发布模式
- 没有断言功能
- 没有widget的debug信息,不能进行断点追踪
- AOT(ahead of time)模式编译,更快速启动和更小的包体积大小,目前Release模式仅支持真机调试
- Profile: 分析模式
- 它基于release的构建模式增加了一些性能监控的实现
- 在Profile模式下可以通过
Flutter Dev tools
和Observatory
监控和测试app性能
通过
flutter run
命令我们可以看到有很多的参数,他们为这个三个模式的运行提供了其他的服务
Flutter run参数
指令 | 解释 |
---|---|
-d, --device-id | 指定需要运行的设备id (prefixes allowed). |
--version | 报告当前的版本 |
--suppress-analytics 运行此命令时禁止分析报告。 | |
--packages | 指定.packages 路径,如果当前目录没有包含.packages ,主要用于查找依赖包路径 |
--debug | 在debug模式下运行 |
--profile | 在profile模式下运行 |
--release | 在release模式下运行 |
--dart-define= |
添加启动时的环境变量,可以通过类似的String.fromEnvironment ,bool.fromEnvironment ,int.fromEnvironment ,double.fromEnvironment 获取,对应项目的多flavor运行非常有用. |
--flavor | 用于指定特定平台的构建,在android中它代表的是products flavor,在Xcode中它代表的是schemes,可以指定对应的xcconfig来构建 |
--trace-startup | 跟踪应用程序的启动然后推出保存到文件 |
--verbose-system-logs | 包括flutter engine的日志 |
--cache-sksl | 仅采用SkSL缓存着色器,而不采用GLSL |
--dump-skp-on-shader-compilation | 转储触发着色器编译的skp,默认关闭,默认关闭 |
--route | 指定哪一个路由将要加载在启动app的时候 |
--vmservice-out-file= |
vmservice uri 记录 |
-t, --target= |
指定需要运行额main.dart文件路径,默认是lib/main.darrt |
--observatory-port | (已经废弃,推荐使用host-vmservice-port代替)用于监听observator调试器给定的端口 |
-device-vmservice-port | 查找vmservice的端口,默认将会接收vmservicce第一个发现的端口 |
--host-vmservice-port | |
--[no-]pub | 在执行命令之前是否执行flutter pub get ,默认为on |
--[no-]track-widget-creation | 跟踪widget创建位置信息,适用于JIT模式下,默认打开 |
--device-user=<10> | 用户工作配置文件标示号码,只适用于android.运行"adb users" 查看可以用的id |
--start-paused | 使用暂停的模式开启,等待一个调试器链接它,不常用 |
--enable-software-rendering | 启动skia的后端渲染,在模拟器测试时非常有用. 默认情况下,flutter将会尝试用OpenGL ,如果没有则使用Vulkan |
--skia-deterministic-rendering | 当与--enable-software-rendering 提供skia的所有的渲染功能 |
--trace-skia | 追中skia的渲染过程信息,这对光栅化线程(raster thread)调试非常有用,也称作为GPU thread |
--endless-trace-buffer | 启动追踪buff功能,可以追踪更多的记录,比如启动内容较多时可以采用trace-startup --endless-trace-buffer |
--trace-systrace | 追踪对应的平台的系统追踪信息,适用于Android和Fuchsia平台 |
--[no-]await-first-frame-when-tracing | 当在执行--trace-startup 的时候是否等待第一帧完成光栅化,默认开启 |
--[no-]use-test-fonts | 允许使用默认的Ahem 字体,减少字体的依赖信息的干扰,只有在debug模式下使用。 |
--[no-]build | 在运行之前先执行构建命令,默认开启 |
--[no-]hot | 执行热重载入,重新assemble所有的widget,不能使用--trace-startup,不会执行main函数,所以无效 |
--pid-file | 指定一个文件去存储进程的pid ,当发送SIGUSR1 执行reload操作,发送SIGUSR2 执行hot restart操作 |
--[no-]fast-start | 是否快速引导构建应用程序,仅支持android |
参考
源代码地址: https://github.com/flutter/flutter.git
https://github.com/flutter/engine.git