zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之字符串类型(string)
    每天一杯C_Visual Studio各个版本的区别和总结
    Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之数字类型(number)
    Python笔记_第一篇_面向过程_第一部分_3.进制、位运算、编码
    Valid Number @python
    正式进驻博客园
    LCT总结
    LCT总结
    bzoj3229 [Sdoi2008]石子合并(非dp的GarsiaWachs算法)
    bzoj3229 [Sdoi2008]石子合并(非dp的GarsiaWachs算法)
  • 原文地址:https://www.cnblogs.com/wwoo/p/flutter-jian-jie.html
Copyright © 2011-2022 走看看