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