摘要


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


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


  • FlutterViewController

  • FlutterView

  • FlutterEngine

  • DartIsolate


FlutterViewController


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


@interface FlutterViewController : UIViewController <FlutterTextureRegistry, FlutterPluginRegistry>- (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<FlutterPluginRegistry>)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<FlutterBinaryMessenger>* binaryMessenger;@end


FlutterViewController 的构造函数


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


- (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<fml::WeakPtrFactory<FlutterViewController>>(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<fml::WeakPtrFactory<FlutterViewController>>(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;}


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


  • 初始化或者替换当前的 FlutterEngine


  • 初始化 FlutterView


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


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


  • 设置 UIInterfaceOrientationMaskUIStatusBarStyle


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


  • FlutterViewController 设置给 FlutterEngine


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


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


FlutterViewController 的 loadView


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


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


FlutterViewController 对 Navigator 的操作


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


- (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


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

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


setInitialRoute 设置流程如下:


DispatchPlatformMessage -> HandleNavigationPlatformMessage -> initial_route_


void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> 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<PlatformMessage> message) { const auto& data = message->data();  rapidjson::Document document;  document.Parse(reinterpretcast<const char*>(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;}


setInitialRoute 最终在 HandleNavigationPlatformMessage 函数中直接被赋值给 initial_route_


setInitialRoute 读取流程如下:


Window.defaultRouteName -> DefaultRouteName -> Engine::DefaultRouteName -> initial_route_


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


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


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


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 文件下面的函数,读取 initial_route_ 的值


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(),  );


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


 Future<dynamic> handleNavigationInvocation(MethodCall methodCall) { switch (methodCall.method) { case 'popRoute': return handlePopRoute(); case 'pushRoute': return handlePushRoute(methodCall.arguments as String);    } return Future<dynamic>.value();  } Future<void> handlePushRoute(String route) async { for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(observers)) { if (await observer.didPushRoute(route)) return;    }  } Future<void> handlePopRoute() async { for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) { if (await observer.didPopRoute()) return;    }    SystemNavigator.pop();  }


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


class WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { @override Future<bool> didPopRoute() async { assert(mounted); final NavigatorState navigator = navigator?.currentState; if (navigator == null) return false; return await navigator.maybePop();  } @override Future<bool> didPushRoute(String route) async { assert(mounted); final NavigatorState navigator = _navigator?.currentState; if (navigator == null) return false;    navigator.pushNamed(route); return true;  }}


handlePopRoute 函数中,如果没有任何一个 observer 返回 true,则最终调用 SystemNavigator.pop(); 来退出应用程序


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


FlutterView


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


  • 初始化时传入 FlutterViewEngineDelegate

  • 创建 flutter::IOSSurface


@protocol FlutterViewEngineDelegate <NSObject>- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type                                  asBase64Encoded:(BOOL)base64Encode;- (flutter::FlutterPlatformViewsController*)platformViewsController;@end@interface FlutterView : UIView- (instancetype)initWithDelegate:(id<FlutterViewEngineDelegate>)delegate                          opaque:(BOOL)opaque NSDESIGNATEDINITIALIZER;- (std::uniqueptr<flutter::IOSSurface>)createSurface:    (std::sharedptr<flutter::IOSGLContext>)context;@end


takeScreenshot:asBase64Encoded: 应该是 FlutterView 渲染的数据源,具体参考 drawLayer:inContext: 的源码


@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<void>(screenshot.data->data())                                length:screenshot.data->size()];  fml::CFRef<CGDataProviderRef> imagedataprovider( CGDataProviderCreateWithCFData(reinterpretcast<CFDataRef>(data)));  fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());  fml::CFRef<CGImageRef> 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<CGBitmapInfo>(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


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


这里不对 IOSSurface 做过多解析,其是建立在三种 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}


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


CALayer -> IOSSurfaceSoftware

CAEAGLLayer -> IOSSurfaceGL

CAMetalLayer -> IOSSurfaceMetal


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


FlutterEngine


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


  • 构造函数,initWithName:project:allowHeadlessExecution,allowHeadlessExecution允许初始化引擎时不强依赖FlutterViewController`

  • 启动引擎,runWithEntrypoint:libraryURI: 可传入自定义的 entrypoint

  • 释放资源,destroyContext

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

  • FlutterViewController 的 get/set

  • 最后是一堆内置的 channel


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


@interface FlutterEngine : NSObject <FlutterTextureRegistry, FlutterPluginRegistry>- (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<FlutterBinaryMessenger> binaryMessenger;@property(nonatomic, readonly, copy, nullable) NSString isolateId;@end


FlutterEngine 的构造


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


  • FlutterDartProject 初始化

  • FlutterPlatformViewsController 的初始化


- (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<fml::WeakPtrFactory<FlutterEngine>>(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 的启动


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


  • FlutterDartProject

  • flutter::ThreadHost

  • flutter::Shell

  • FlutterObservatoryPublisher

  • FlutterPlatformViewsController


FlutterEngine 的启动,主要是两个事情


  • createShell

  • launchEngine


- (BOOL)runWithEntrypoint:(NSString)entrypoint libraryURI:(NSString)libraryURI { if ([self createShell:entrypoint libraryURI:libraryURI]) {    [self launchEngine:entrypoint libraryURI:libraryURI];  } return _shell != nullptr;}


createShell


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


  • 初始化 MessageLoop

  • 初始化 ThreadHost

  • 设置 oncreateplatform_view 回调

  • 设置 oncreaterasterizer 回调

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

  • 创建 shell,最终是启动 Isolate

  • 创建 FlutterPlatformViewsController

  • 创建 FlutterObservatoryPublisher

  • 设置 PlatformView 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<flutter::PlatformView> oncreateplatformview =      [](flutter::Shell& shell) { return std::makeunique<flutter::PlatformViewIOS>(shell, shell.GetTaskRunners());      };  flutter::Shell::CreateCallback<flutter::Rasterizer> oncreaterasterizer =      [](flutter::Shell& shell) { return std::makeunique<flutter::Rasterizer>(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;}


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


launchEngine


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


- (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<void(Engine::RunStatus)> 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 函数,最核心的是这行代码 PrepareAndLaunchIsolate,最终整个流程跑下来就是为了启动 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<DartIsolate> 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<PlatformMessage> serviceidmessage =        fml::MakeRefCounted<flutter::PlatformMessage>(            kIsolateChannel, std::vector<uint8t>(serviceid.begin(), serviceid.end()), nullptr);    HandlePlatformMessage(serviceidmessage);  } return isolaterunning ? Engine::RunStatus::Success                         : Engine::RunStatus::Failure;}


DartIsolate


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


  • 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<std::string>& 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;}


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


  • _getStartMainIsolateFunction

  • _runMainZoned


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 来绘制界面,drawLayer 时会调用 takeScreenshot 来获取 Flutter 界面的光栅图

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

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

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

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

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


Flutter 运行流程


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


  • 寻找 DartLibrary

  • 定位到 Entrypoint

  • 创建 FlutterEngine,传入 DartLibrary 和 Entrypoint

  • 创建 FlutterViewControllerFlutterView

  • 设置 FlutterEngineviewController

  • 创建 shell,启动 Dart VM

  • 加载 DartLibrary,运行 dart 的 Entrypoint

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


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

(文章来源:InfoQ)