Flutter简介

它Google推出的跨平台语言,同时支持android,iOSwindows,使用skia图形渲染引擎,渲染效率可达60FPS以上。

Flutter框架

如下图,它主要分为以下三层

  1. Framework: 采用纯dart编写,主要负责界面构建,手势,布局,基础服务的包装和提供,围绕着Widget树,Element树,Render树的构建和管理而展开的
  2. Engine,提供了dartvm服务器,dart运行的隔离空间,文本渲染,图形渲染,跨平台接口
  3. 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负责不同的任务.

  1. Platform Task Runner: 在初始化Engine的时候,它会将当前线程设置为PlatformTaskRunner的线程, 它是与Native交互的的桥梁,官方要求所有与native的交互都必须要在PlatformTask,这是因为flutter没有多线概念,为了防止资源竞争和不可预知的错误
  2. UI Task Runner: 它是flutter engine的核心,主要负责dart端main函数代码的执行,所有的widget树,element树,render树的构建,以及所有运行在mainIsolate下的任务.
  3. IO Task Runner: 负责比较费时的I/O操作,主要是针对图片的读取和解码操作,避免阻塞其他的TaskRunner,如Platfom Task Runner对应的是Native的主线程,阻塞时间过长会导致WatchDog超时,被系统强制杀掉。
  4. GPU Task Runner: 对应的是Raste线程,执行GPU的绘制任务,将来自UI Task Runner处理好的RenderObject树(图层树),进行光栅化操作,转化为pixel buffer,提交给GPU执行。

Flutter构建模式

  1. Debug: 调试模式
    • 在这个模式下,支持assert断言
    • 可以通过Observatory分析和调试代码,比如方法的调用次数,总时间话费
    • 支持JIT(Just in time)模式,通过hot reload,快速的的将中间产物代码提交给dart vm执行.
  2. Release: 发布模式
    • 没有断言功能
    • 没有widget的debug信息,不能进行断点追踪
    • AOT(ahead of time)模式编译,更快速启动和更小的包体积大小,目前Release模式仅支持真机调试
  3. Profile: 分析模式
    • 它基于release的构建模式增加了一些性能监控的实现
    • 在Profile模式下可以通过Flutter Dev toolsObservatory监控和测试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

posted @ 2020-10-12 01:05  阿甘左  阅读(534)  评论(0编辑  收藏  举报