摘要
本文主要是針對 Flutter 在 iOS 上是如何運(yùn)行起來的源碼進(jìn)行串聯(lián)筷黔,總結(jié)大致的運(yùn)行流程业汰。
涉及到的關(guān)鍵類有以下幾個(gè):
- FlutterViewController
- FlutterView
- FlutterEngine
- DartIsolate
FlutterViewController
Flutter 嵌入原生應(yīng)用必須有個(gè)載體,從這個(gè)點(diǎn)入手,在 Flutter Engine 源碼中的 API 的入口點(diǎn)是 FlutterViewController
,對其頭文件源碼做精簡番官,大致如下
@interface FlutterViewController : UIViewController <FlutterTextureRegistry, FlutterPluginRegistry>
- (instancetype)initWithEngine:(FlutterEngine*)engine
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER;
- (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 的構(gòu)造函數(shù)
FlutterViewController 有兩個(gè)構(gòu)造函數(shù),本質(zhì)上是一樣的钢属,第一個(gè)構(gòu)造函數(shù)是谷歌為了在存在多個(gè) FlutterViewController
的場景下為了讓使用者能復(fù)用 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::make_unique<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::make_unique<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;
}
在構(gòu)造函數(shù)中主要做了這么幾件事情:
初始化或者替換當(dāng)前的
FlutterEngine
初始化
FlutterView
初始化正在發(fā)生的手勢集合
加載閃屏頁,傳入
FlutterEngine
的構(gòu)造函數(shù)沒有這項(xiàng)淆党,應(yīng)該是考慮了多FlutterViewController
的場景下不好頻繁加載閃屏頁設(shè)置
UIInterfaceOrientationMask
和UIStatusBarStyle
添加一系列的通知酷师,包括
Application
的生命周期,鍵盤事件染乌,Accessibility
的事件等將
FlutterViewController
設(shè)置給FlutterEngine
第二個(gè)構(gòu)造函數(shù)中還多了這行代碼山孔,第一個(gè)構(gòu)造函數(shù)把這個(gè)調(diào)用延后了而已
[_engine.get() createShell:nil libraryURI:nil];
FlutterViewController 的 loadView
在 loadView
函數(shù)中,設(shè)置了 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
提供了三個(gè)接口允許我們在原生端對 dart 的 Navigator
直接進(jìn)行操作
- (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,這個(gè)過程略微特殊台谊,并不會(huì)在 dart 端直接接收 channel 信息,
而是在引擎層面做了處理譬挚,web_ui 不在本文的解析范疇锅铅,這里直接洗跟原生相關(guān)的點(diǎn)
setInitialRoute
設(shè)置流程如下:
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(reinterpret_cast<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");
initial_route_ = std::move(route->value.GetString());
return true;
}
setInitialRoute
最終在 HandleNavigationPlatformMessage
函數(shù)中直接被賦值給 initial_route_
。
setInitialRoute
讀取流程如下:
Window.defaultRouteName
-> DefaultRouteName
-> Engine::DefaultRouteName
-> initial_route_
可以看到减宣,關(guān)鍵字 native
盐须,這是 dart 為了方便綁定 C/C++ 導(dǎo)出方法而添加的關(guān)鍵字,對應(yīng)的 key 是 Window_defaultRouteName
class Window {
String get defaultRouteName => _defaultRouteName();
String _defaultRouteName() native 'Window_defaultRouteName';
}
可以找到在引擎層的 flutter 命名空間下漆腌,有下面這個(gè)函數(shù)贼邓,注冊了對應(yīng)的導(dǎo)出函數(shù)阶冈,這里對應(yīng)的是 DefaultRouteName
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"Window_defaultRouteName", DefaultRouteName, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
{"Window_respondToPlatformMessage", _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(Dart_NativeArguments args) {
std::string routeName =
UIDartState::Current()->window()->client()->DefaultRouteName();
Dart_SetReturnValue(args, tonic::StdStringToDart(routeName));
}
再往下就是到 engine.cc 文件下面的函數(shù),讀取 initial_route_
的值
std::string Engine::DefaultRouteName() {
if (!initial_route_.empty()) {
return initial_route_;
}
return "/";
}
至此塑径,完成了在原生端設(shè)置 defaultRouteName女坑,在 dart 端獲取該值的流程。
pushRoute and popRoute
實(shí)現(xiàn)方式主要還是通過引擎內(nèi)置的 navigationChannel
通知 dart 端统舀,對應(yīng)的在 dart 端 SystemChannels
類中匆骗,存在對應(yīng)的 channel
static const MethodChannel navigation = MethodChannel(
'flutter/navigation',
JSONMethodCodec(),
);
最終處理 pushRoute
和 popRoute
的邏輯在 WidgetsBinding
類中,主要是以下幾個(gè)函數(shù)
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();
}
這段代碼表示只有調(diào)用的方法返回 true
時(shí)才中斷誉简,每個(gè) handle 函數(shù)具體的處理邏輯是通過某個(gè) WidgetsBindingObserver
來實(shí)現(xiàn)了碉就,繼續(xù)跟進(jìn)找到如下代碼
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
函數(shù)中,如果沒有任何一個(gè) observer
返回 true
闷串,則最終調(diào)用 SystemNavigator.pop();
來退出應(yīng)用程序
class SystemNavigator {
static Future<void> pop({bool animated}) async {
await SystemChannels.platform.invokeMethod<void>('SystemNavigator.pop', animated);
}
}
FlutterView
FlutterView
并沒有太多功能瓮钥,主要是兩點(diǎn):
- 初始化時(shí)傳入
FlutterViewEngineDelegate
- 創(chuàng)建
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 NS_DESIGNATED_INITIALIZER;
- (std::unique_ptr<flutter::IOSSurface>)createSurface:
(std::shared_ptr<flutter::IOSGLContext>)context;
@end
takeScreenshot:asBase64Encoded:
應(yīng)該是 FlutterView
渲染的數(shù)據(jù)源,具體參考 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.frame_size.isEmpty()) {
return;
}
NSData* data = [NSData dataWithBytes:const_cast<void*>(screenshot.data->data())
length:screenshot.data->size()];
fml::CFRef<CGDataProviderRef> image_data_provider(
CGDataProviderCreateWithCFData(reinterpret_cast<CFDataRef>(data)));
fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
fml::CFRef<CGImageRef> image(CGImageCreate(
screenshot.frame_size.width(), // size_t width
screenshot.frame_size.height(), // size_t height
8, // size_t bitsPerComponent
32, // size_t bitsPerPixel,
4 * screenshot.frame_size.width(), // size_t bytesPerRow
colorspace, // CGColorSpaceRef space
static_cast<CGBitmapInfo>(kCGImageAlphaPremultipliedLast |
kCGBitmapByteOrder32Big), // CGBitmapInfo bitmapInfo
image_data_provider, // CGDataProviderRef provider
nullptr, // const CGFloat* decode
false, // bool shouldInterpolate
kCGRenderingIntentDefault // CGColorRenderingIntent intent
));
const CGRect frame_rect =
CGRectMake(0.0, 0.0, screenshot.frame_size.width(), screenshot.frame_size.height());
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, CGBitmapContextGetHeight(context));
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, frame_rect, image);
CGContextRestoreGState(context);
}
@end
后面我們會(huì)看到 FlutterViewEngineDelegate
實(shí)際上是被 FlutterEngine
實(shí)現(xiàn)了烹吵。
這里不對 IOSSurface
做過多解析骏庸,其是建立在三種 layer 之上的,可以在編譯期選擇使用何種渲染方式
- 如果是模擬器年叮,則使用正常的 CALayer
- 使用 Metal 渲染的情形則使用 CAMetalLayer
- 使用 OpenGL 渲染的情形則使用 CAEAGLLayer
+ (Class)layerClass {
#if TARGET_IPHONE_SIMULATOR
return [CALayer class];
#else // TARGET_IPHONE_SIMULATOR
#if FLUTTER_SHELL_ENABLE_METAL
return [CAMetalLayer class];
#else // FLUTTER_SHELL_ENABLE_METAL
return [CAEAGLLayer class];
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // TARGET_IPHONE_SIMULATOR
}
在 createSurface
函數(shù)中主要是分別創(chuàng)建三種對應(yīng)的 IOSSurface
CALayer -> IOSSurfaceSoftware
CAEAGLLayer -> IOSSurfaceGL
CAMetalLayer -> IOSSurfaceMetal
再往下的渲染實(shí)際上就要交給 FlutterEngine
自身了具被。
FlutterEngine
FlutterEngine
對外暴露的接口不算多,主要就這么幾點(diǎn)
- 構(gòu)造函數(shù)只损,
initWithName:project:allowHeadlessExecution
一姿,allowHeadlessExecution允許初始化引擎時(shí)不強(qiáng)依賴
FlutterViewController` - 啟動(dòng)引擎,
runWithEntrypoint:libraryURI:
可傳入自定義的entrypoint
- 釋放資源跃惫,
destroyContext
- 語義樹是否建立叮叹,
ensureSemanticsEnabled
,關(guān)于語義樹文檔比較少爆存,大概是殘疾人模式下需要用到的東西 -
FlutterViewController
的 get/set - 最后是一堆內(nèi)置的 channel
我們主要關(guān)心引擎的構(gòu)造蛉顽、啟動(dòng)、釋放和 FlutterViewController
就差不多了先较,FlutterTextureRegistry
, FlutterPluginRegistry
不在本文關(guān)注范圍內(nèi)
@interface FlutterEngine : NSObject <FlutterTextureRegistry, FlutterPluginRegistry>
- (instancetype)initWithName:(NSString*)labelPrefix
project:(nullable FlutterDartProject*)project
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;
- (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 的構(gòu)造
FlutterEngine
在構(gòu)造時(shí)携冤,要關(guān)注的有幾下兩點(diǎn):
-
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::make_unique<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 的啟動(dòng)
FlutterEngine
層面,需要關(guān)注以下一些類:
- FlutterDartProject
- flutter::ThreadHost
- flutter::Shell
- FlutterObservatoryPublisher
- FlutterPlatformViewsController
FlutterEngine
的啟動(dòng)闲勺,主要是兩個(gè)事情
- 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
的源碼比較多曾棕,做了下精簡,主要是以下幾點(diǎn):
- 初始化
MessageLoop
- 初始化
ThreadHost
- 設(shè)置
on_create_platform_view
回調(diào) - 設(shè)置
on_create_rasterizer
回調(diào) - 初始化
flutter::TaskRunners
菜循,如果開啟embedded_views_preview
則 使用當(dāng)前線程的TaskRunner
作為 gpu 線程的TaskRunner
- 創(chuàng)建
shell
翘地,最終是啟動(dòng) Isolate - 創(chuàng)建
FlutterPlatformViewsController
- 創(chuàng)建
FlutterObservatoryPublisher
- 設(shè)置
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> on_create_platform_view =
[](flutter::Shell& shell) {
return std::make_unique<flutter::PlatformViewIOS>(shell, shell.GetTaskRunners());
};
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
[](flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell, shell.GetTaskRunners());
};
if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
fml::MessageLoop::GetCurrent().GetTaskRunner(), // gpu
_threadHost.ui_thread->GetTaskRunner(), // ui
_threadHost.io_thread->GetTaskRunner() // io
);
// Create the shell. This is a blocking operation.
_shell = flutter::Shell::Create(std::move(task_runners), // task runners
std::move(settings), // settings
on_create_platform_view, // platform view creation
on_create_rasterizer // rasterzier creation
);
} else {
flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
_threadHost.gpu_thread->GetTaskRunner(), // gpu
_threadHost.ui_thread->GetTaskRunner(), // ui
_threadHost.io_thread->GetTaskRunner() // io
);
// Create the shell. This is a blocking operation.
_shell = flutter::Shell::Create(std::move(task_runners), // task runners
std::move(settings), // settings
on_create_platform_view, // platform view creation
on_create_rasterizer // rasterzier creation
);
}
if (_shell != nullptr) {
[self setupChannels];
if (!_platformViewsController) {
_platformViewsController.reset(new flutter::FlutterPlatformViewsController());
}
_publisher.reset([[FlutterObservatoryPublisher alloc] init]);
[self maybeSetupPlatformViewChannels];
}
return _shell != nullptr;
}
這里可以看到會(huì)啟動(dòng)四個(gè) TaskRunner
,分別為 platform,gpu, ui,io,但實(shí)際上并不一定對應(yīng)四個(gè)線程衙耕。
launchEngine
launchEngine
實(shí)際上還是在 shell
上進(jìn)行的操作
- (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);
}));
}
再跟下去昧穿,最終會(huì)到[shell > common > engine.cc] 里面的 run
函數(shù),最核心的是這行代碼 PrepareAndLaunchIsolate
橙喘,最終整個(gè)流程跑下來就是為了啟動(dòng) Isolate
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return RunStatus::Failure;
}
auto isolate_launch_status =
PrepareAndLaunchIsolate(std::move(configuration));
if (isolate_launch_status == Engine::RunStatus::Failure) {
FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
return isolate_launch_status;
} else if (isolate_launch_status ==
Engine::RunStatus::FailureAlreadyRunning) {
return isolate_launch_status;
}
std::shared_ptr<DartIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
bool isolate_running =
isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
if (isolate_running) {
tonic::DartState::Scope scope(isolate.get());
if (settings_.root_isolate_create_callback) {
settings_.root_isolate_create_callback();
}
if (settings_.root_isolate_shutdown_callback) {
isolate->AddIsolateShutdownCallback(
settings_.root_isolate_shutdown_callback);
}
std::string service_id = isolate->GetServiceId();
fml::RefPtr<PlatformMessage> service_id_message =
fml::MakeRefCounted<flutter::PlatformMessage>(
kIsolateChannel,
std::vector<uint8_t>(service_id.begin(), service_id.end()),
nullptr);
HandlePlatformMessage(service_id_message);
}
return isolate_running ? Engine::RunStatus::Success
: Engine::RunStatus::Failure;
}
DartIsolate
對 PrepareAndLaunchIsolate
函數(shù)做下精簡时鸵,剩下兩個(gè)點(diǎn)
- PrepareIsolate
- RunFromLibrary
Engine::RunStatus Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) {
// ……
if (!isolate_configuration->PrepareIsolate(*isolate)) {
return RunStatus::Failure;
}
if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
return RunStatus::Failure;
}
return RunStatus::Success;
}
主要看看 RunFromLibrary
做了什么
- 查找 entrypoint
- 調(diào)用 entrypoint 的函數(shù),
InvokeMainEntrypoint
bool DartIsolate::RunFromLibrary(const std::string& library_name,
const std::string& entrypoint_name,
const std::vector<std::string>& args,
fml::closure on_run) {
tonic::DartState::Scope scope(this);
auto user_entrypoint_function =
Dart_GetField(Dart_LookupLibrary(tonic::ToDart(library_name.c_str())),
tonic::ToDart(entrypoint_name.c_str()));
auto entrypoint_args = tonic::ToDart(args);
if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
return false;
}
phase_ = Phase::Running;
if (on_run) {
on_run();
}
return true;
}
再看看 InvokeMainEntrypoint
做了什么渴杆,源碼做了精簡寥枝,主要就這兩步,我們可以在 dart 端找到對應(yīng)的函數(shù)
_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 庫磁奖,這是 fuchsia 下的庫囊拜。
總結(jié)
Flutter 運(yùn)行于 iOS 之上,從源碼層面看比搭,有以下幾點(diǎn)收獲:
- 復(fù)用了現(xiàn)有的三類 CALayer 來繪制界面冠跷,
drawLayer
時(shí)會(huì)調(diào)用takeScreenshot
來獲取 Flutter 界面的光柵圖 - 在原生端不會(huì)建立對應(yīng)的 語義樹,需要額外生成
- Flutter 自身會(huì)起一個(gè)完全獨(dú)立的線程環(huán)境來運(yùn)行身诺,我們需要關(guān)注的是四個(gè)
TaskRunner
蜜托,Platform TaskRunner 不一定是獨(dú)立的線程 - Platform TaskRunner,原生端跟 Flutter 的所有交互都會(huì)在 Platform TaskRunner 進(jìn)行處理
- dart 端可以通過
native
關(guān)鍵字調(diào)用 C/C++ 的函數(shù)霉赡,獲取基本類型的數(shù)據(jù)返回值橄务,性能比 channel 要好 -
FlutterViewController
將所有的手勢交互相關(guān)的都轉(zhuǎn)發(fā)給 FlutterEngine
Flutter 運(yùn)行流程
對整個(gè) Flutter 運(yùn)行的流程可以大致總結(jié)如下,主要是側(cè)重在引擎?zhèn)妊鳎琩art 那邊的流程不展開蜂挪,僅供參考:
- 尋找 DartLibrary
- 定位到 Entrypoint
- 創(chuàng)建
FlutterEngine
,傳入 DartLibrary 和 Entrypoint - 創(chuàng)建
FlutterViewController
嗓化,FlutterView
- 設(shè)置
FlutterEngine
的viewController
- 創(chuàng)建 shell棠涮,啟動(dòng) Dart VM
- 加載 DartLibrary,運(yùn)行 dart 的 Entrypoint
- 截取 Dart UI 的界面并光柵化并 繪制 CALayer
作者其它文章