Categories
程式開發

Flutter引擎源碼解讀-Flutter是如何在iOS上運行起來的


摘要

官方文檔在原生側的說明很少,更多的時候需要從源碼去尋找答案,本文主要是針對 Flutter 在 iOS 上是如何運行起來的源碼進行串聯,總結大致的運行流程。

涉及到的關鍵類有以下幾個:

FlutterViewControllerFlutterViewFlutterEngineDartIsolate

FlutterViewController

Flutter 嵌入原生應用必須有個載體,從這個點入手,在 Flutter Engine 源碼中的 API 的入口點是 FlutterViewController,對其頭文件源碼做精簡,大致如下

@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 有兩個構造函數,本質上是一樣的,第一個構造函數是谷歌為了在存在多個 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(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;
}

在構造函數中主要做了這麼幾件事情:

初始化或者替換當前的 FlutterEngine

初始化 FlutterView

初始化正在發生的手勢集合

加載閃屏頁,傳入 FlutterEngine 的構造函數沒有這項,應該是考慮了多 FlutterViewController 的場景下不好頻繁加載閃屏頁

設置 UIInterfaceOrientationMask 和 UIStatusBarStyle

添加一系列的通知,包括 Application 的生命週期,鍵盤事件,Accessibility的事件等

將 FlutterViewController 設置給 FlutterEngine

第二個構造函數中還多了這行代碼,第一個構造函數把這個調用延後了而已

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

FlutterViewController 的 loadView

在 loadView 函數中,設置了 FlutterViewController 的 view,並判斷是否需要加載閃屏頁,可以通過重寫 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 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: "

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;
}

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

最終處理 pushRoute 和 popRoute 的邏輯在 WidgetsBinding 類中,主要是以下幾個函數

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

這段代碼表示只有調用的方法返回 true 時才中斷,每個 handle 函數具體的處理邏輯是通過某個 WidgetsBindingObserver 來實現了,繼續跟進找到如下代碼

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;
}
}

handlePopRoute 函數中,如果沒有任何一個 observer 返回 true,則最終調用 SystemNavigator.pop(); 來退出應用程序

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

FlutterView

FlutterView 並沒有太多功能,主要是兩點:

初始化時傳入 FlutterViewEngineDelegate創建 flutter::IOSSurface

@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

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

後面我們會看到 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

- (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 的構造

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(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 層面,需要關注以下一些類:

FlutterDartProjectflutter::ThreadHostflutter::ShellFlutterObservatoryPublisherFlutterPlatformViewsController

FlutterEngine 的啟動,主要是兩個事情

createShelllaunchEngine

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

這裡可以看到會啟動四個 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 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)

再跟下去,最終會到[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 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

對 PrepareAndLaunchIsolate 函數做下精簡,剩下兩個點

PrepareIsolateRunFromLibrary

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;
}

再看看 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創建 FlutterViewController,FlutterView設置 FlutterEngine 的 viewController創建 shell,啟動 Dart VM加載 DartLibrary,運行 dart 的 Entrypoint截取 Dart UI 的界面並光柵化並 繪製 CALayer

本文主要是對整個源碼流程做了一個串聯,更多細節無法在一篇文章中闡述清楚。