Bootstrap

Flutter引擎源码解读-Flutter是如何在iOS上运行起来的

摘要

官方文档在原生侧的说明很少,更多的时候需要从源码去寻找答案,本文主要是针对 Flutter 在 iOS 上是如何运行起来的源码进行串联,总结大致的运行流程。

涉及到的关键类有以下几个:

  • FlutterViewController

  • FlutterView

  • FlutterEngine

  • DartIsolate

FlutterViewController

Flutter 嵌入原生应用必须有个载体,从这个点入手,在 Flutter Engine 源码中的 API 的入口点是 ,对其头文件源码做精简,大致如下

@interface FlutterViewController : UIViewController 

- (instancetype)initWithEngine:(FlutterEngine)engine
                       nibName:(nullable NSString)nibName
                        bundle:(nullable NSBundle)nibBundle NSDESIGNATEDINITIALIZER;

- (instancetype)initWithProject:(nullable FlutterDartProject)project
                        nibName:(nullable NSString)nibName
                         bundle:(nullable NSBundle)nibBundle NSDESIGNATEDINITIALIZER;

- (void)handleStatusBarTouches:(UIEvent)event;

- (void)setFlutterViewDidRenderCallback:(void (^)(void))callback;

- (NSString)lookupKeyForAsset:(NSString)asset;

- (NSString)lookupKeyForAsset:(NSString)asset fromPackage:(NSString)package;

- (void)setInitialRoute:(NSString)route;

- (void)popRoute;

- (void)pushRoute:(NSString)route;

- (id)pluginRegistry;

@property(nonatomic, readonly, getter=isDisplayingFlutterUI) BOOL displayingFlutterUI;

@property(strong, nonatomic) UIView splashScreenView;

- (BOOL)loadDefaultSplashScreenView;

@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque;

@property(weak, nonatomic, readonly) FlutterEngine engine;

@property(nonatomic, readonly) NSObject* binaryMessenger;

@end

FlutterViewController 的构造函数

FlutterViewController 有两个构造函数,本质上是一样的,第一个构造函数是谷歌为了在存在多个 的场景下为了让使用者能复用 而开放的。

- (instancetype)initWithEngine:(FlutterEngine)engine
                       nibName:(nullable NSString)nibName
                        bundle:(nullable NSBundle)nibBundle {
  NSAssert(engine != nil, @"Engine is required");
  self = [super initWithNibName:nibName bundle:nibBundle];
  if (self) {
    viewOpaque = YES;
    engine.reset([engine retain]);
    engineNeedsLaunch = NO;
    flutterView.reset([[FlutterView alloc] initWithDelegate:engine opaque:self.isViewOpaque]);
    weakFactory = std::makeunique>(self);
    ongoingTouches = [[NSMutableSet alloc] init];

    [self performCommonViewControllerInitialization];
    [engine setViewController:self];
  }

  return self;
}

- (instancetype)initWithProject:(nullable FlutterDartProject)project
                        nibName:(nullable NSString)nibName
                         bundle:(nullable NSBundle)nibBundle {
  self = [super initWithNibName:nibName bundle:nibBundle];
  if (self) {
    viewOpaque = YES;
    weakFactory = std::makeunique>(self);
    engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter"
                                              project:project
                               allowHeadlessExecution:NO]);
    flutterView.reset([[FlutterView alloc] initWithDelegate:engine opaque:self.isViewOpaque]);
    [engine.get() createShell:nil libraryURI:nil];
    engineNeedsLaunch = YES;
    _ongoingTouches = [[NSMutableSet alloc] init];
    [self loadDefaultSplashScreenView];
    [self performCommonViewControllerInitialization];
  }

  return self;
}

在构造函数中主要做了这么几件事情:

  • 初始化或者替换当前的

  • 初始化

  • 初始化正在发生的手势集合

  • 加载闪屏页,传入 的构造函数没有这项,应该是考虑了多 的场景下不好频繁加载闪屏页

  • 设置 和

  • 添加一系列的通知,包括 的生命周期,键盘事件,的事件等

  • 将 设置给

第二个构造函数中还多了这行代码,第一个构造函数把这个调用延后了而已

    [_engine.get() createShell:nil libraryURI:nil];

FlutterViewController 的 loadView

在 函数中,设置了 的 ,并判断是否需要加载闪屏页,可以通过重写 的 get 方法返回 的方式彻底不加载闪屏页

- (void)loadView {
  self.view = _flutterView.get();
  self.view.multipleTouchEnabled = YES;
  self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

  [self installSplashScreenViewIfNecessary];
}

FlutterViewController 对 Navigator 的操作

提供了三个接口允许我们在原生端对 dart 的 直接进行操作

- (void)setInitialRoute:(NSString)route {
  [[engine.get() navigationChannel] invokeMethod:@"setInitialRoute" arguments:route];
}

- (void)popRoute {
  [[engine.get() navigationChannel] invokeMethod:@"popRoute" arguments:nil];
}

- (void)pushRoute:(NSString)route {
  [[_engine.get() navigationChannel] invokeMethod:@"pushRoute" arguments:route];
}

setInitialRoute

在 iOS 端通过 来告诉 dart 具体的 initialRoute,这个过程略微特殊,并不会在 dart 端直接接收 channel 信息,

而是在引擎层面做了处理,web_ui 不在本文的解析范畴,这里直接洗跟原生相关的点

设置流程如下:

-> ->

void Engine::DispatchPlatformMessage(fml::RefPtr message) {
  if (message->channel() == kLifecycleChannel) {
    if (HandleLifecyclePlatformMessage(message.get()))
      return;
  } else if (message->channel() == kLocalizationChannel) {
    if (HandleLocalizationPlatformMessage(message.get()))
      return;
  } else if (message->channel() == kSettingsChannel) {
    HandleSettingsPlatformMessage(message.get());
    return;
  }

  if (runtime_controller_->IsRootIsolateRunning() &&
      runtime_controller_->DispatchPlatformMessage(std::move(message))) {
    return;
  }

  // If there's no runtime_, we may still need to set the initial route.
  if (message->channel() == kNavigationChannel) {
    HandleNavigationPlatformMessage(std::move(message));
    return;
  }

  FML_DLOG(WARNING) << "Dropping platform message on channel: "
                    << message->channel();
}

bool Engine::HandleNavigationPlatformMessage(
    fml::RefPtr message) {
  const auto& data = message->data();

  rapidjson::Document document;
  document.Parse(reinterpretcast(data.data()), data.size());
  if (document.HasParseError() || !document.IsObject())
    return false;
  auto root = document.GetObject();
  auto method = root.FindMember("method");
  if (method->value != "setInitialRoute")
    return false;
  auto route = root.FindMember("args");
  initialroute_ = std::move(route->value.GetString());
  return true;
}

最终在 函数中直接被赋值给 。

读取流程如下:

-> -> ->

可以看到,关键字 ,这是 dart 为了方便绑定 C/C++ 导出方法而添加的关键字,对应的 key 是

class Window {
  String get defaultRouteName => defaultRouteName();
  String defaultRouteName() native 'Window_defaultRouteName';
}

可以找到在引擎层的 flutter 命名空间下,有下面这个函数,注册了对应的导出函数,这里对应的是

void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({
      {"Window_defaultRouteName", DefaultRouteName, 1, true},
      {"Window_scheduleFrame", ScheduleFrame, 1, true},
      {"WindowsendPlatformMessage", SendPlatformMessage, 4, true},
      {"WindowrespondToPlatformMessage", RespondToPlatformMessage, 3, true},
      {"Window_render", Render, 2, true},
      {"Window_updateSemantics", UpdateSemantics, 2, true},
      {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
      {"Window_reportUnhandledException", ReportUnhandledException, 2, true},
      {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
  });
}

void DefaultRouteName(DartNativeArguments args) {
  std::string routeName =
      UIDartState::Current()->window()->client()->DefaultRouteName();
  DartSetReturnValue(args, tonic::StdStringToDart(routeName));
}

再往下就是到 engine.cc 文件下面的函数,读取 的值

std::string Engine::DefaultRouteName() {
  if (!initialroute.empty()) {
    return initialroute;
  }
  return "/";
}

至此,完成了在原生端设置 defaultRouteName,在 dart 端获取该值的流程。

pushRoute and popRoute

实现方式主要还是通过引擎内置的 navigationChannel 通知 dart 端,对应的在 dart 端 SystemChannels 类中,存在对应的 channel

static const MethodChannel navigation = MethodChannel(
      'flutter/navigation',
      JSONMethodCodec(),
  );

最终处理 和 的逻辑在 类中,主要是以下几个函数

  Future handleNavigationInvocation(MethodCall methodCall) {
    switch (methodCall.method) {
      case 'popRoute':
        return handlePopRoute();
      case 'pushRoute':
        return handlePushRoute(methodCall.arguments as String);
    }
    return Future.value();
  }

  Future handlePushRoute(String route) async {
    for (final WidgetsBindingObserver observer in List.from(observers)) {
      if (await observer.didPushRoute(route))
        return;
    }
  }

  Future handlePopRoute() async {
    for (final WidgetsBindingObserver observer in List.from(_observers)) {
      if (await observer.didPopRoute())
        return;
    }
    SystemNavigator.pop();
  }

这段代码表示只有调用的方法返回 时才中断,每个 handle 函数具体的处理逻辑是通过某个 来实现了,继续跟进找到如下代码

class WidgetsAppState extends State with WidgetsBindingObserver {

  @override
  Future didPopRoute() async {
    assert(mounted);
    final NavigatorState navigator = navigator?.currentState;
    if (navigator == null)
      return false;
    return await navigator.maybePop();
  }

  @override
  Future didPushRoute(String route) async {
    assert(mounted);
    final NavigatorState navigator = _navigator?.currentState;
    if (navigator == null)
      return false;
    navigator.pushNamed(route);
    return true;
  }
}

函数中,如果没有任何一个 返回 ,则最终调用 来退出应用程序

class SystemNavigator {
  static Future pop({bool animated}) async {
    await SystemChannels.platform.invokeMethod('SystemNavigator.pop', animated);
  }
}

FlutterView

并没有太多功能,主要是两点:

  • 初始化时传入

  • 创建

@protocol FlutterViewEngineDelegate 

- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
                                  asBase64Encoded:(BOOL)base64Encode;

- (flutter::FlutterPlatformViewsController*)platformViewsController;

@end

@interface FlutterView : UIView

- (instancetype)initWithDelegate:(id)delegate
                          opaque:(BOOL)opaque NSDESIGNATEDINITIALIZER;
- (std::uniqueptr)createSurface:
    (std::sharedptr)context;

@end

应该是 渲染的数据源,具体参考 的源码

@implementation FlutterView
- (void)drawLayer:(CALayer)layer inContext:(CGContextRef)context {
  if (layer != self.layer || context == nullptr) {
    return;
  }

  auto screenshot = [delegate takeScreenshot:flutter::Rasterizer::ScreenshotType::UncompressedImage
                              asBase64Encoded:NO];

  if (!screenshot.data || screenshot.data->isEmpty() || screenshot.framesize.isEmpty()) {
    return;
  }

  NSData data = [NSData dataWithBytes:constcast(screenshot.data->data())
                                length:screenshot.data->size()];

  fml::CFRef imagedataprovider(
      CGDataProviderCreateWithCFData(reinterpretcast(data)));

  fml::CFRef colorspace(CGColorSpaceCreateDeviceRGB());

  fml::CFRef image(CGImageCreate(
      screenshot.framesize.width(),      // sizet width
      screenshot.framesize.height(),     // sizet height
      8,                                  // sizet bitsPerComponent
      32,                                 // sizet bitsPerPixel,
      4  screenshot.framesize.width(),  // sizet bytesPerRow
      colorspace,                         // CGColorSpaceRef space
      staticcast(kCGImageAlphaPremultipliedLast |
                                kCGBitmapByteOrder32Big),  // CGBitmapInfo bitmapInfo
      imagedataprovider,                                 // CGDataProviderRef provider
      nullptr,                                             // const CGFloat* decode
      false,                                               // bool shouldInterpolate
      kCGRenderingIntentDefault                            // CGColorRenderingIntent intent
      ));

  const CGRect framerect =
      CGRectMake(0.0, 0.0, screenshot.framesize.width(), screenshot.framesize.height());

  CGContextSaveGState(context);
  CGContextTranslateCTM(context, 0.0, CGBitmapContextGetHeight(context));
  CGContextScaleCTM(context, 1.0, -1.0);
  CGContextDrawImage(context, frame_rect, image);
  CGContextRestoreGState(context);
}
@end

后面我们会看到 实际上是被 实现了。

这里不对 做过多解析,其是建立在三种 layer 之上的,可以在编译期选择使用何种渲染方式

  • 如果是模拟器,则使用正常的 CALayer

  • 使用 Metal 渲染的情形则使用 CAMetalLayer

  • 使用 OpenGL 渲染的情形则使用 CAEAGLLayer

+ (Class)layerClass {
#if TARGETIPHONESIMULATOR
  return [CALayer class];
#else  // TARGETIPHONESIMULATOR
#if FLUTTERSHELLENABLEMETAL
  return [CAMetalLayer class];
#else   // FLUTTERSHELLENABLEMETAL
  return [CAEAGLLayer class];
#endif  //  FLUTTERSHELLENABLEMETAL
#endif  // TARGETIPHONE_SIMULATOR
}

在 函数中主要是分别创建三种对应的

CALayer -> IOSSurfaceSoftware

CAEAGLLayer -> IOSSurfaceGL

CAMetalLayer -> IOSSurfaceMetal

再往下的渲染实际上就要交给 自身了。

FlutterEngine

对外暴露的接口不算多,主要就这么几点

  • 构造函数,,allowHeadlessExecutionFlutterViewController`

  • 启动引擎, 可传入自定义的

  • 释放资源,

  • 语义树是否建立,,关于语义树文档比较少,大概是残疾人模式下需要用到的东西

  • 的 get/set

  • 最后是一堆内置的 channel

我们主要关心引擎的构造、启动、释放和 就差不多了,, 不在本文关注范围内

@interface FlutterEngine : NSObject 

- (instancetype)initWithName:(NSString)labelPrefix
                     project:(nullable FlutterDartProject)project
      allowHeadlessExecution:(BOOL)allowHeadlessExecution NSDESIGNATEDINITIALIZER;

- (BOOL)runWithEntrypoint:(nullable NSString)entrypoint libraryURI:(nullable NSString)uri;

- (void)destroyContext;

- (void)ensureSemanticsEnabled;

@property(nonatomic, weak) FlutterViewController viewController;

@property(nonatomic, readonly, nullable) FlutterMethodChannel localizationChannel;

@property(nonatomic, readonly) FlutterMethodChannel navigationChannel;

@property(nonatomic, readonly) FlutterMethodChannel platformChannel;

@property(nonatomic, readonly) FlutterMethodChannel textInputChannel;

@property(nonatomic, readonly) FlutterBasicMessageChannel lifecycleChannel;

@property(nonatomic, readonly) FlutterBasicMessageChannel systemChannel;

@property(nonatomic, readonly) FlutterBasicMessageChannel settingsChannel;

@property(nonatomic, readonly) NSObject binaryMessenger;

@property(nonatomic, readonly, copy, nullable) NSString isolateId;

@end

FlutterEngine 的构造

在构造时,要关注的有几下两点:

  • 初始化

  • 的初始化

- (instancetype)initWithName:(NSString)labelPrefix
                     project:(FlutterDartProject)project
      allowHeadlessExecution:(BOOL)allowHeadlessExecution {
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  NSAssert(labelPrefix, @"labelPrefix is required");

  allowHeadlessExecution = allowHeadlessExecution;
  labelPrefix = [labelPrefix copy];

  weakFactory = std::makeunique>(self);

  if (project == nil)
    dartProject.reset([[FlutterDartProject alloc] init]);
  else
    dartProject.reset([project retain]);

  pluginPublications = [NSMutableDictionary new];
  platformViewsController.reset(new flutter::FlutterPlatformViewsController());

  _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];

  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
  [center addObserver:self
             selector:@selector(onMemoryWarning:)
                 name:UIApplicationDidReceiveMemoryWarningNotification
               object:nil];

  return self;
}

FlutterEngine 的启动

层面,需要关注以下一些类:

  • FlutterDartProject

  • flutter::ThreadHost

  • flutter::Shell

  • FlutterObservatoryPublisher

  • FlutterPlatformViewsController

的启动,主要是两个事情

  • createShell

  • launchEngine

- (BOOL)runWithEntrypoint:(NSString)entrypoint libraryURI:(NSString)libraryURI {
  if ([self createShell:entrypoint libraryURI:libraryURI]) {
    [self launchEngine:entrypoint libraryURI:libraryURI];
  }

  return _shell != nullptr;
}

createShell

的源码比较多,做了下精简,主要是以下几点:

  • 初始化

  • 初始化

  • 设置 回调

  • 设置 回调

  • 初始化 ,如果开启 则 使用当前线程的 作为 gpu 线程的

  • 创建 ,最终是启动 Isolate

  • 创建

  • 创建

  • 设置 channels

- (BOOL)createShell:(NSString)entrypoint libraryURI:(NSString)libraryURI {

  // ……

  fml::MessageLoop::EnsureInitializedForCurrentThread();

  threadHost = {threadLabel.UTF8String, flutter::ThreadHost::Type::UI |
                                         flutter::ThreadHost::Type::GPU |
                                         flutter::ThreadHost::Type::IO};

  flutter::Shell::CreateCallback oncreateplatformview =
      [](flutter::Shell& shell) {
        return std::makeunique(shell, shell.GetTaskRunners());
      };

  flutter::Shell::CreateCallback oncreaterasterizer =
      [](flutter::Shell& shell) {
        return std::makeunique(shell, shell.GetTaskRunners());
      };

  if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
    flutter::TaskRunners taskrunners(threadLabel.UTF8String,                          // label
                                      fml::MessageLoop::GetCurrent().GetTaskRunner(),  // platform
                                      fml::MessageLoop::GetCurrent().GetTaskRunner(),  // gpu
                                      threadHost.uithread->GetTaskRunner(),          // ui
                                      threadHost.iothread->GetTaskRunner()           // io
    );
    // Create the shell. This is a blocking operation.
    shell = flutter::Shell::Create(std::move(taskrunners),  // task runners
                                    std::move(settings),      // settings
                                    oncreateplatformview,  // platform view creation
                                    oncreaterasterizer      // rasterzier creation
    );
  } else {
    flutter::TaskRunners taskrunners(threadLabel.UTF8String,                          // label
                                      fml::MessageLoop::GetCurrent().GetTaskRunner(),  // platform
                                      threadHost.gputhread->GetTaskRunner(),         // gpu
                                      threadHost.uithread->GetTaskRunner(),          // ui
                                      threadHost.iothread->GetTaskRunner()           // io
    );
    // Create the shell. This is a blocking operation.
    shell = flutter::Shell::Create(std::move(taskrunners),  // task runners
                                    std::move(settings),      // settings
                                    oncreateplatformview,  // platform view creation
                                    oncreaterasterizer      // rasterzier creation
    );
  }

  if (shell != nullptr) {
    [self setupChannels];
    if (!platformViewsController) {
      platformViewsController.reset(new flutter::FlutterPlatformViewsController());
    }
    publisher.reset([[FlutterObservatoryPublisher alloc] init]);
    [self maybeSetupPlatformViewChannels];
  }

  return _shell != nullptr;
}

这里可以看到会启动四个 ,分别为 platform,gpu, ui,io,但实际上并不一定对应四个线程。

launchEngine

实际上还是在 上进行的操作

- (void)launchEngine:(NSString)entrypoint libraryURI:(NSString)libraryOrNil {
  // Launch the Dart application with the inferred run configuration.
  self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint
                                                            libraryOrNil:libraryOrNil]);
}

void Shell::RunEngine(RunConfiguration run_configuration) {
  RunEngine(std::move(run_configuration), nullptr);
}

void Shell::RunEngine(RunConfiguration run_configuration,
                      std::function result_callback) {
  auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
                 result_callback](Engine::RunStatus run_result) {
    if (!result_callback) {
      return;
    }
    platform_runner->PostTask(
        [result_callback, run_result]() { result_callback(run_result); });
  };
  FML_DCHECK(is_setup_);
  FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

  if (!weak_engine_) {
    result(Engine::RunStatus::Failure);
  }
  fml::TaskRunner::RunNowOrPostTask(
      task_runners_.GetUITaskRunner(),
      fml::MakeCopyable(
          [run_configuration = std::move(run_configuration),
           weak_engine = weak_engine_, result]() mutable {
            if (!weak_engine) {
              FML_LOG(ERROR)
                  << "Could not launch engine with configuration - no engine.";
              result(Engine::RunStatus::Failure);
              return;
            }
            auto run_result = weak_engine->Run(std::move(run_configuration));
            if (run_result == flutter::Engine::RunStatus::Failure) {
              FML_LOG(ERROR) << "Could not launch engine with configuration.";
            }
            result(run_result);
          }));
}

再跟下去,最终会到[shell > common > engine.cc] 里面的 run 函数,最核心的是这行代码 ,最终整个流程跑下来就是为了启动 Isolate

Engine::RunStatus Engine::Run(RunConfiguration configuration) {
  if (!configuration.IsValid()) {
    FMLLOG(ERROR) << "Engine run configuration was invalid.";
    return RunStatus::Failure;
  }

  auto isolatelaunchstatus =
      PrepareAndLaunchIsolate(std::move(configuration));
  if (isolatelaunchstatus == Engine::RunStatus::Failure) {
    FMLLOG(ERROR) << "Engine not prepare and launch isolate.";
    return isolatelaunchstatus;
  } else if (isolatelaunchstatus ==
             Engine::RunStatus::FailureAlreadyRunning) {
    return isolatelaunchstatus;
  }

  std::sharedptr isolate =
      runtimecontroller->GetRootIsolate().lock();

  bool isolaterunning =
      isolate && isolate->GetPhase() == DartIsolate::Phase::Running;

  if (isolaterunning) {
    tonic::DartState::Scope scope(isolate.get());

    if (settings.rootisolatecreatecallback) {
      settings.rootisolatecreatecallback();
    }

    if (settings.rootisolateshutdowncallback) {
      isolate->AddIsolateShutdownCallback(
          settings.rootisolateshutdowncallback);
    }

    std::string serviceid = isolate->GetServiceId();
    fml::RefPtr serviceidmessage =
        fml::MakeRefCounted(
            kIsolateChannel,
            std::vector(serviceid.begin(), serviceid.end()),
            nullptr);
    HandlePlatformMessage(serviceidmessage);
  }

  return isolaterunning ? Engine::RunStatus::Success
                         : Engine::RunStatus::Failure;
}

DartIsolate

对 函数做下精简,剩下两个点

  • PrepareIsolate

  • RunFromLibrary

Engine::RunStatus Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) {

  // ……

  if (!isolate_configuration->PrepareIsolate(*isolate)) {

    return RunStatus::Failure;

  }

  if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),

                               configuration.GetEntrypoint(),

                               settings.dartentrypoint_args)) {

    return RunStatus::Failure;

  }

  return RunStatus::Success;

}

主要看看 RunFromLibrary 做了什么

  • 查找 entrypoint

  • 调用 entrypoint 的函数,InvokeMainEntrypoint

bool DartIsolate::RunFromLibrary(const std::string& libraryname,
                                 const std::string& entrypointname,
                                 const std::vector& args,
                                 fml::closure onrun) {
  tonic::DartState::Scope scope(this);

  auto userentrypointfunction =
      DartGetField(DartLookupLibrary(tonic::ToDart(libraryname.cstr())),
                    tonic::ToDart(entrypointname.cstr()));

  auto entrypointargs = tonic::ToDart(args);

  if (!InvokeMainEntrypoint(userentrypointfunction, entrypointargs)) {
    return false;
  }
  phase = Phase::Running;
  if (onrun) {
    onrun();
  }
  return true;
}

再看看 做了什么,源码做了精简,主要就这两步,我们可以在 dart 端找到对应的函数

static bool InvokeMainEntrypoint(Dart_Handle user_entrypoint_function,
                                 Dart_Handle args) {

  Dart_Handle start_main_isolate_function =
      tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
                             "_getStartMainIsolateFunction", {});

  if (tonic::LogIfError(tonic::DartInvokeField(
          Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
          {start_main_isolate_function, user_entrypoint_function, args}))) {
    FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
    return false;
  }

  return true;
}

再往下就是 tonic 库,后面可能会在其它文章中对 tonic 库进行梳理。

总结

Flutter 运行于 iOS 之上,从源码层面看,有以下几点收获:

  • 复用了现有的三类 CALayer 来绘制界面, 时会调用 来获取 Flutter 界面的光栅图

  • 在原生端不会建立对应的 语义树,需要额外生成

  • Flutter 自身会起一个完全独立的线程环境来运行,我们需要关注的是四个 ,Platform TaskRunner 不一定是独立的线程

  • Platform TaskRunner,原生端跟 Flutter 的所有交互都会在 Platform TaskRunner 进行处理

  • dart 端可以通过 关键字调用 C/C++ 的函数,获取基本类型的数据返回值,性能比 channel 要好

  • 将所有的手势交互相关的都转发给 FlutterEngine

Flutter 运行流程

对整个 Flutter 运行的流程可以大致总结如下,主要是侧重在引擎侧,dart 那边的流程不展开,仅供参考:

  • 寻找 DartLibrary

  • 定位到 Entrypoint

  • 创建 ,传入 DartLibrary 和 Entrypoint

  • 创建 ,

  • 设置 的

  • 创建 shell,启动 Dart VM

  • 加载 DartLibrary,运行 dart 的 Entrypoint

  • 截取 Dart UI 的界面并光栅化并 绘制 CALayer

本文主要是对整个源码流程做了一个串联,更多细节无法在一篇文章中阐述清楚。