摘要
本文首要是针对 Flutter 在 iOS 上是怎么运转起来的源码进行串联,总结大致的运转流程。
涉及到的要害类有以下几个:
- FlutterViewController
- Flut * D @ 2 E v `terView
- FlutterEngine
- DartIsolate
FlutterViewController
Flutter 嵌入原生运用必须有个载体,从这个点下手,在 Flutter Engine 源码中的 API 的入口点是 FlutterViewController
,对其头文件M h B ? 8 h c g源码做精简,大致如下
@interface FlutH t OterViewControl9 V e G Tler : UIView] R Q U N $ - ^Cont8 ? - h p g M uroller <FlutterTextureRegistry, FlutterPluginRegistry>
- (instancetype)initWithEngv A J M s m O Aine:(FlutterEngine*)engine
nibName:(nullable NSString*)nibName
bunde R f 6le:(k x O G Onullable NSBundle*)nibBundle NSG w 9 v V y_DESIGNATED_INITIALIZER;
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibName
bundle:(X V K I 0nu@ t H ; Xllable NSBundle*)nibBundle NS_DESIGNATEDD 1 : f f F P }_IJ H w } u q 8 *NITIALIZER;
-/ } F y a (void)handleStatusBarTouches:(UIEvent*)event;
- (vk m g s e / G 8 /oid)setFlutter! % B 3 WViewX ; ! m [DidRi 7 2enderCallback:(void (^)(void))callback;
- (NSString*)lookupKeyForAsset:(NSString*)asse^ t h =t;
- (NSString*)lookupKeyForAsG ( ~ @ 1 { Y ? 2set:(NSStF 4 +rin6 Z k 4 Q t R g*)asset fromPackage:(NSString*)package;
- (void)setInitialRoute:(NSString*)route;
-! ( R G (voidU o J T $ J)popRoute;
- (void)pushRoute:(NSString*)route;
- (id<Flu[ { g N TtterPluginRegistry>)pluginRegistry;
@property(nonatomic, readonly, getter=isDisplayingFlutter+ 8 3 B H ^ ~ *UI) BOOL displayingFlutterUI;
@property(strong, nonatomic) UIView* sF / R Z , R u bplashScreenView;
- (BOOL)loadDefau= ` c 3 / m |ltSplashS2 c _ | I N B F `creenView;
@property(nonatomic, getter=isViewOpaque)Q e / w 5 b BOOL viewOpaque;
@property(weak, nonatomic, reH , y @adonly) FlutterEngine* engine;
@property(nonatomic, readonly) NSObject<FlutterBinaryMessenger>* binaryMessenger;
@= 0 O E 5 Uend
FlutterViewContr= , Uoller 的u h o 3 *结构函数
FlutterViewController 有两个结构函数,本质上是一样的,第一个结构函数是谷歌为了在存在多个 FlutterViewCond , & * ^ h 6 R ctrollerh @ L t ( c D
的场景下为了让运用者能复用 FlutterEngine
而敞开的。
- (instancetype)initWithEngine:(FlutterEngineu u Q E F*)engine
nibName:(nullable NSStrin) / R A fg*)nibName
bundle:(nullable NSBundle*)nibBundle {
NSAssert(engine != nil, @"Ent ( / ^ 7gine is required");
self = [super initWiF A _ E b 9 tthNibName:nibName bundle:nibBundle];
if (self) {
_viewOpaque = YES;
_engine.re8 y iset([engine retain]);
_engineNeedsLau, 0 )nC $ z 9 e e f .ch = NO;
_flutterView.reset([[FlutterView alloc]C j y I initWithDelegate:_engine opaque:self.isU | G = z 5 NViewOpaque]);
_weakFactory = std::md V 7 5 Iake_uniquey h + C C I Q s<fml::WeakPtrFactory<FlutterViewControlV N oler&g_ x V 5 Ft;>= : i O U(self)r 7 X 4 [ h [;
_ongoI Y C c n v [ {ingTouches = [[NSMutableSet alloc] init];
[self performCommonViewControllerInitialization];
[engine setViewController:self];
}
retur` d Q x h z M 4n self;
}
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibNw ? h { tame
bundle:(nullableb ; 7 N d NSBundle*)nibBundle {
self = [super initWithNibName:nibName bundle:nibBundle];
if (self) {
_viewOpaque = YES;
_weakFactory = std::make_unique<fml::WeakD J x I G ePtrFactory<FlutterViewController>>(self);
_engine.reset([[FlutterEn, U fgine alloc] initWithName:E A 6 ; s 1 A@"io.flutter"
project:project
allowHeadlessExecution:NO]);
_flutterVie% ! x N Vw.reset([[FlutterView alloc] initWithDelegate:_engine opaque:se+ ) + H 0lf.isViewOpaque]);
[_engine.get() createShell:nil libraryURI:% E l c L ; x f ]nil];
_engineNeedsLaunch = YES;
_ongoingTouches = [[NSMutableSet alloc] init];
[self loadDefaultSplashScreenView];
[self performCommonViewCe ! ; LontrollerInitial1 W v % J u , v rization];
}
return self;
}
在结构函数中首要做了这么d V q :几件工作:
-
初始化或者替换当时的
FlutterEngine
-
初始化
FlutterView
-
初始化正在发生的手势调集
-
加载闪屏页,传入
FlutterEngine
的结构函数没有这项,应该是考虑了多FlutterViewController
的场景下l Y 9 3 X不好频频加载闪屏页 -
设置
UIInterfaB % S PceOrientationMask
和UIStatusBarStyleK - - - d V
-
增加一系列的告诉,包含
Applicat} C o k Jion
的生命周期,键盘工作,Accessi1 g |bility
的工作等 -
将
FlutterViewCj l L - I * Lontroller
设置给FlutterR % ^ ( 7Engine
第二个结构函数中还多了这行代码,第一个结构函数把这个调用延后了而已
[_engine.get() createSh % 6 Rell9 T 5 b : ; L:nil libraryURI:nil];
FlutterViewController 的 loadView
在 loadView
函数中,设置了 FlutterViewController
的 view
,并判断是否需求加载闪屏页,能够经过重写 splashScreenView
的 get 办法回来 nil
的方式完全不加载闪屏页
- (void)loadView {
self.view = _flutterView.gl Z Wet();
self.view.multK : yipleTouchEnabled = YES;
self.view.autoresizingMask = UIViewAutoresizinU P `gFlexibleWidth | UIViewAutoresizingFlexibleHeigh& f z f _ l lt;
[self installSplashScreenViewIfw G p P X Y E 6Necessary];
}
FlutterViewControld : b 8 k G Pler 对 Navigator 的操作
FlutterViewControllee X G M Z `r
供给了三个接口答应* F W I h咱们在原生端对 dart 的 Navigator
直接进行操作
- (void)setInitialRoute:(NSString*)route {
[[_engine.get() navigationChannel] invokeMethodn C U : Q , g ^ K:@"sN C P N L %etIniM X m S $ `tialRoute" arguments:route];
}
- (void)popRoute {
[[_engine.get() navigationChannel] invokeMK w 6 l 0 ( } 6ethod:g 3 d d Z / 7 j@"popRoute" arguments:nil];
}
- (void)pushRoute:(NSString*)route {
[$ I = 8 : ^[_engine.get() navigationChannel] invokeMethod:@"pushRoute" arguments:route]G 0 l;
}
setInitialRoute
setInitialRoute
在 iOS 端经过 navil j { n ~ v M _ 2gationChannel
来告诉 dart 详细的 initialRoute,这个过程稍微特别,并不会在 dart 端直接接收 channel 信息,
而是在引擎层面做d b 3 ( n = N d s了处理,web_ui 不在本文的解析范畴,这儿直接洗跟原生相关的点
setInitialRoute
设置流程如下:
Disz b a X 5 XpatchPz d p 1 dlatfT r =ormMessage
-> HandleNavigationPlatformMel $ u x F / ;ssage
-> initial_route_
void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() ==^ 6 X , B K ) kLifecycleChannel) {
if (HandleLifecyclePlatformMessage(message.get()))
return;
} else if (message->channel() == kLp Y 7 u 4ocalizationChaa v Lnnel) {
if (HandleLocalizationPlatw 9 3 : j - I i IformMessage(messo O P ? 2 2 aage.get()))
return;
} else if (messaL ! s Kge->channel() == kSet! ) Y ~ N stingsChannel) {
HandleSettingsPlatformMS a N [ * D L iessage(message.get());
return;
}
i: , gf (runtime_controller_->IsRootIsolateRunning() &&
runtime_controller_->D^ / L A % ; ?ispatchPlatformF F j J zMessage(std::move(message))) {
return;
}
// If there's no r~ ~ F Puntime_, we may stl ) - 6 K {ill need to set the initial route.
if (message->ch1 ? E W r 7 Tannel() == kNavit 3 $ qgationChannel) {
HandleNavigationPlatf} g mormMessage(std::move(message));
return;
}
FML_DLOG(WARNIX A g 6 3 3 nNG) << "Dropping platform message on channel: "
<< message->channel();
}
bool Engine::HandleNavigationPlatformMessage(
fml::RefPtr<PlatformMessage>S ; V U; message)g R & W h S {! j - w g
const auto& da, 6 8 v ~ta = message->data();
rapidjson::Document document;
document.Parse(reinterpret_cast<const charB U + ]*>(data.data())a % i o + Z t 1, data.size());
if (d; v * ^ % : E t Cocum. . { u ent.HasParseError() || !document.IsObjB * V M { ( v 8 8ect())
return false;
autoA F ~ root = document.GetObject();
au5 M %to method = root.Fm _indMember("mp * 2 3 (ethod2 e = % h");
if (method->value != "setInitialRoute")
return false;
auto route = root.FindMember("args");! 6 U G
initial_route_ = std::move(route->value.GetString());
return true;
}. , x * s 3 _ T -
setInitialRoute
终究在 HandleNavigationPlatformMesW M _sage
函数中直# ? B n w接被赋值给 initial_route_
。
setInitialRoute
读取流程如下:
Window.defaultRouteName
-> DefaultRouteName
-> Engine::DS j 1 XefaultRouteNX M & O ` Z [ i 9ame
-> iniv f Jtial_route_
能够看到,要害字 native
,这是 dart 为了便利绑定 C/C++ 导出办法而F V Q a ] J i增加的要害字,对E s W _ – m X L u应的 key 是 Window_defaultRouteName
class Window {
String get defauS F } T c <RouteNaf o @ _ ^me => _defaultRc 9 v / _ D r & mouteName();
String _defaultRouteName() native 'Window_defaultRouteName';
}
能够找到在引擎层 s d d c T f的 flutter 命名空间下,有下面这个函数,注册了对应的导出函数,这儿对应的是 Default% Z S dRoute` F J r ! : W O pName
void Window::RegisterNatives0 9 N G G % r B ?(tonic::DartLibraryNatives* natives) {
natiu ^ Xves->Register({
{"Window_defU e : C M t p ~aultRouteName", DefaultRouteNu O {ame, 1, true},
{"Window_s2 ( K B qcheduleFrame", SchedulN j Y r +eFrame, 1,: : 6 E true},
{"Window_sendPlatformMessage", _Se- = i 9ndPlatformMessage, 4, true},
{"Window_res( # G , 5pondToPlatformMessage", _RespondT/ ! Y oPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"WindowY U U g 5 U_updateSemantics"C B p,I h S U{ * - : { 7 {pdateSemantics, 2, true},
{"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
{"Window_reportUnhandledException", ReportUnhandledException, 2, true},
{"Window_setNe@ s / r 1edsReportTimingsE ] c ^ z o k", SetNeedsReportTimings, 2, true},
});
}
void DefaultRouteName(Dart_NativeArguments args) {
std::string routeName =
UIDartState::Current()->window()->client()->DefaultRouteName();
Dart_SetRetur_ t ) R ` %nValue(args, tonic::StdStringTi ( woDart(routeName));
}
再往下便是到 engine.cc 文件下面的函数,读取 initiai @ J 6 j ol_route_
的值
std::strw s Xing Engine::DefaultRouteName() {
i* h N J U A u 9f (!iB s unitial3 | ; E b | I 2_route_.empty()) {
return initial_route_;
}
return "/";
}a t c
至此,完成了在原+ r [ k u T V生端设置 defaultRoA 0 R 1 T / & t muteName,在 darP _ p *t 端获取该值的流程。
pushRoute aO k n j Z pnd popRoute
完成方式首要仍是经过引擎内置– ,的 navigationChannel
告诉 dart 端,对应的在 dart 端 SystemChan 1 y W Lnels
类中,存在对应的 channel
static const MethodChannel navigation = MethodChannel(
'fluttez K ; C mr/navigation',
JSONMethodCodec(),
);
终究处 S k理 pushRoute
和 popRoute
的逻辑在 WidgetsBinding
类中,首要是以下几个函数
Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
switch (methodCallx N G @ 5.method) {
case 'popRoute':
return handlePopRoute();
case 'pushRoute':
return handlePushRoute(methodCall.arguments as SU 8 U 7 *tring);
}
return Future<dynamic>.value();
}
Future<void> hanw 9 R a a D u &dlePushRoute(String route) async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver[ 5 W w>.from(_observers)) {
if (await observer^ f c.didPushRoute(route))
return;
}
}
Future<void> handlePopRoute() a v E ! + vsync {
for (final WidgetsBindingOk r f ~ h y ybserver observer in List<WidgetsBindingObserver>.from(_observ$ ( d 3 h k Q Z Kers)v y i t) {
if (await observer.didPopRoute())
return;
}
SystemNavigator.pop();
}
这段代码表明只有调用的办法回来 true
时才中断,每个 handle 函数详细的处理逻辑是经过某个 WidgetsBindingObserver
来完成了,继续跟进找到如下代码
class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
@override
Future<bool> didPopRoute(, J 1 Q z ! m 7 M) asynh V a B & h J :c {
assert(mounted);
final NavigatorState navigator = _navigator?.currentState;
if (navigator == null)
return false;
return await navigator.maybePop();
}
@override
Future<bool> dida ^ e . l IPushRoute(String route) async {
assertw + U T * r(mounted);
final NavigatorState navigator = _navigator?.currena @ Z / p l h # YtState;
ifA 0 a 2 t ~ (navigator == null)
return false;
navigator.pushT I h M : %Name# W S Q = fd(roP r o 2 Eute);
return true;
}
}
handlePopRoute
函数中,假如没h E k有任何一个 observer
回来 true
,则终究调w 3 b u $ } ? } x用 SystemNavigator.pop();
来退出运用程序h : q
class SystemNavigator {
static Future<void> poL V n | o |p({bool animated}I m ^ | &) asyncB P _ G / 5 {
await SystemChannels.platform.invokeMethod<void>('SystemNavc . ( e S Eigator.pop', animated);
}
}
FlutterVic + 6 8 S R o * Uew
FlutterView
并没有太多功能,首要是两点:
- 初始化时传入
FlutterViewEngineDelegate
- 创立
flutter::IOSSurface
@protocol FlutterViewEngineDelegate <NSObject>
- (flutter::Rasterizer::Scre[ u c _ B z : zenshot)takeScreenshot:(flutter::Rasterizer::ScreenB 7 7 ] + $ QshotType)type
asBase64Encoded:(BOOL)base64Encode;
- ([ k ) 9 r s R s qflutter::FlutterPlatformViewsController*)platformViews* 7 T {Controller;
@end
@interface FlutterV/ x R ~iew : UIView
- (instancetyp- h k ^ % }e)initWithDelegate:(id<FlutterViewEngineDelegate>)delegate
opP - 1 w h o aque:(BOOL)opaque NSY @ ? I_E S #DESIGNATED_INITIALIZERG 6 h g K;
- (std::u+ ? w 3 ) I 5 Tni - s ! ] D M Yque_ptr<flutter::IOSSurface5 5 O v @ A L 4>)createSurface:
(std::shared_ptr<flutter::IOSGLCod f | $ o entext>)contex0 k tt;
@end
takeScreenshot:asBase64Encoded:
应该是n # C ( i ! m FlutterVA x , 9iew
烘托的数据源,详细参考 drawLayV v 6 l . | l | Oer:inContext:
的源码
@implementation Fluttf 2 l Y xerView
- (void)drawLayer:(CALayer*)laye? u O ` zr inContext:(CGContextRef)context {
if (layer != self.layer || context == nullptr) {
return;
}
auto screenshot = [_delegate takeScreenshot:flutter::Rasterizer::S l # C G xcreenshotType::UncompressedImage
asBase64Encoded:NO];
if (!screenshot.data || screenshot.data->isEmptyD o w 0 N() || 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(
CGDataProviderCa % nreateWithCFData(reinterpret_cast<CFDataRef>(data)));
fml::CFRef<CGColorSx ! j G a }paceRef> colorspace(CGColorSpaceCreateDeviceRGB());
fml::CFRef<CGImageRef> image(CGImageCreaK ` 0 Hte(
screenshot.frc = x -ame_g 1 = U ] C : fsize.width(), // size_t width
screenshot.frame_size.height(), // s% ` F ; }ize_t height
8, // size_t biw 7 t f ctsPerComponent
32, // size_t bitsPerPixel,
4 * screenshot.frame_size.width(), // sig s S i i f kze_t bytesPerRow
colorspace, // CGColorSpaceR: H ^ W J vef space
static_cast<CGBitmapInfo>(kCGImageAlphaPremultipliedLast |
kCGBitmapByteOrder32Big), // CGBitmapInfo bitmf % T 0 J [ k g zapInfo
image_data_provider, // CGDataProviderRef provider
nulo - L 5lptr, // co| M S 3 ( C ^nst CGFloat* decode
false, // bool should_ / jInterpolate
kCGRenderingInt( A & v C | p L entDefault // CGColorRenderingIntent intent
));
const CGRect frame_rect =
CGRectMake(0.0, 0.0, screenshot.frame_size.+ } 9 c & J Pwidth(), screenshot.fr p / ` v $ I w _ame_size.height());
CGCoN P ] D b F R _ :ntextSaveGStatF [ h , +e(context);
CGContextTranslateCTM(context, 0.0, CGBitmapContextGetHeight(context));
CGContextScaleCTM(context, 1.0, -1.0);
CGContexX ?tDrawImage(context, frame_rect, image);
CGContextRestoreGState(context);
}
@end
后面咱们会看到 FlutterViewEngiB 1 k 9 f y I 9 LneDelegate
实际上是被 FlutterEngine
完成了。
这儿不对 IOSSi , G o 6 t . b qurface
做过多解析,其是树立z n # 4 . k *在三种 layer 之上的,B ( ^ ? _ )能够在编译期选择运用何种烘托方式
- 假如是模拟器,则运用 h 1 c F o o A –正常的 CALayer
- 运用 Metal 烘托的景象则运用 CAMetalLayer
- 运用 OpenGL 烘托的景象则运用 CA= 1 P d A G M JEAGLLayer
+b S E (Class)layerClO % + 6 &ass {
#if TARGET_IPHONE_SIMULATOR
retur: b 5 s J cn [CAC ~ D } mLayer class];
#else // TARGET_IPHONE_SIMULATOR
#if FLUTTER_SHELL_ENAB| { S RLE_M@ = , 4ETAL
return [CAMeta% W - [ 5 Z H $lLayer class];
#else // FLUTTERt K F_SHELL_ENABLE_META2 T y l 2 q r ]L
return [CAEAGLLF b 4 } p y {ayer class];
#endif // FLUTTER_SHELL_ENABLEk . 3 R (_ME` D r a 4 O G mTAL
#endif // TARGET_IPHONE_SIMULATOR
}
在 createSurface
函数中首要是分别创立三C 7 { Q $ f ` z U种对应的 IOSSurface
CALayer -> IOSSurface3 – H F O 3 F Y gSoftware
CAs J ^ | 8 n { j nEAGLLayer -&E h #gp G N @ +t; IOSSurfaceG x m O 5 m 2L
CAMetalLayer -> IOSSurfaceMetal
再往下的烘托实际上就要交给 FlutterEngine
本身了。
FlutterEnK B : ^ m a Pgine
FlutterEngine
对外暴露的接口不算多,首要就这么几点
- 结构函数,
initWithName:project:allowHeadlessE~ F @ C Y Sxecution
,allowHeadlessExecution答应初始化引擎时不强依靠
FlutterViewController/ % j` - 发动引擎,
runWithEntrypoint:libraryURI:
可传入自定义的entrypoins 7 ] Wt
- 释放资源,
deL & H T L : + WstroyContex( P t i F mt
- 语义树是否树立,
ensureSemanticsEnabled
,关于语义树文档比较少,大概是残疾人模式下需求用到的东西 -
FlutterViewContz 2 0 y % r 8roller
的 get/set - 最后是一堆内置的 channel
咱们首要关心引擎的结构、发动、释放和 FlutterViewController
就差不多了,FlutterTextureRegistryO Q p K + o M / Q
, FlutterP- W D u IluginRegistry
不在本文重视范围内
@interface FlutterEngine : NSObject <FlutterTextureRegn Q J 2istry, FlutterPluginRegist[ H R B M b B 4ry>
- (instancetype)initWithName:(NSStrin1 q L m p T Og*)labelPrefix
project:(nullable FlutterDartProject*)project
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;2 i ) ; C J J ) H
- (Bh : M X t { FOOL)runWithEntrypoint:(nullable NSString*)entrypoint libr7 [ F +aryURI:(nullable NSStringR 2 z d*)uri;
- (void)destroyContext;
- (void)ensureSemanticsEnabled;
@property(nonatomi| R u ` ] 4c, weak) FlutterViewCg % o y 0 E Vontroller* viewController;
@property(nonatomic, readonly, nullable) FlutterMethodChannel* lok S DcalizationChannel;
@property(nonatomic, readonly) FlutterMethodChann| * ` # b R k n Cel* navigationChannel;
@property(nonatomic, readonly) FlutterMethodChannel* platformChannel;
@prope- ` ? N J z ~ y 9rty(nonatomic, readonly) FlutterMethodChax ; k : j Znnel* textInputChannel;
@property(nonatomic, readonly) FlutterBasicMessageChannel* lifecycleChannel;
@propertyL W D 8 0 L * d(nonatomic, readonly) FlutterBasicMessageCha# W w | z } ] mnnel* systemCh& [ ! P Oannel;
@property(nonatomic, readonly) FlutterBasicMessp f e xageChaA O B n # X O -nnel* settingsChc F 8 Nannel;
@property(nonatomv 4 b 9 2 Oic, readonly) NSObject<FlutterBinaryMessenger>* binaryMes@ C T ; 6 f }senger;) k z `
@property(nonatomic, readonly, copy,{ . ] nu; u P P S +llable) NSString* isolateId;w i C = a z ;
@end
FlutterE( ^ M d 1 mngine 的结构
FlutterEngine
在结构时,要重视的有几下两点:
-
FlutterDartProject
初始v ; 4 3 Z化 -
FlutterPlatformViewsController
的初始化
- (instancetype)initWithName:(NSString*)labelPrefix
projece V J T ! . I n Jt:(FlutterDartProject*)project
allowHeadlessExecuti^ f u @on:(BOOL)allowHeadlessExecution {
self = [super init];
NSAssert(self, @"Super init cannot be nil");
NSAssert(labelPrefix, @"labelPrefix& @ G 5 $ j is required");
_allowHeadlessExecution = allowHeadlessExecution;
_labelPrefix = [labelPrefix copy];
_weakFactory = std::make_unique<fml::Wp l ? h - &eakPtrFactory<FlutterEngine&gm i 0 j 2 4t;>(self);
if (project == nil)
_dartP A g t n krojectP Z 9 [.reset2 q r f 4 % u([[FlutterDartProject alloc] init]);
else
_dartProject.reset([project retain]);
_pluginPublications = [NSMutabla + L g ( z geDictio6 A E R q 3 bnary new];
_platformViewsController.reset(new flutter::Fl7 $ b F Y 8 8 tutterPlatformViewsController());
_binaryMessenger = [[FlutterBinaryMessengerRelay alla J & } b _ ]oc] initWithParent:A m h ) 7 $ 6 _ eself];
NSNotificationCentem A 4 .r* center = [NSC } 0 n f p }NotificationCenter defaultCenter];
[center addObserver:self
se2 D m R n l n ylector:@selector(onMemoryWarning:)
name:UIApplication= C | M U d 8DidReceiveMemoryWarningNr ( i zotification
object:nil];
return self;
}
FlutterEngine 的发动
FlutterEngine
层面,需求重视以下一些类:
- FlutterDarN S S ? WtProjectv * Z ` $ M W % }
- flutter::ThreadHost
- flutter::Shell
- FlutterObservatn Z M QoryPublisher
- FlutterPlatformViewsController
Fl# b 4 W 1 B ; H SutterEngine
的发动,首要是两个工作
- createShell
- launchEngine
- (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*7 + & n)libraryURI {
if ([self cr; g , c L OeateShell:entrypoint libraryURI:libraryURI]) {
[N ^ 8self launchEngine:entrypoint libraryURI:libraryURI];
}
return _shell != nullptr;
}
createShell
createShell
的源码比较多,做了下精简,首要是以下几点:
- 初始化
MessageLoop
- 初始化
ThreadHost
- 设置
on_create_platform_view
回调 - 设置
on_create_rasterizer
回调 - 初始化
flutter::TaskRunners
,假如敞开embedded_views_preview
则 运用当时线程的TaskRunner
作为 gpu 线程的TaskRunner
- 创立
shell
,终究是发动 IsO g y *olate - 创立
Flutte? T ?rPlatformViewsCop W % ; 2ntroller
- 创立
Flutterp ) ` , N w PObservatoryPublisher
- 设置
PlatformView
chann( { = t 1 { G Iels
- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI| A k {
// ……
fml::MessageLoop::EnsureInitializedForCurrentThr2 } H & ( ^ / gead();
_threadHost = {threadLabel.UTF8Str$ ! $ : ? d ping, flutter::ThreadHos. ? T + o N ` g Jt::Type::UI |
flutter::ThreadHost::Type::GPU |
flutter::ThreadHost::Type::IO};
flutter::Shell::CreateCallback<9 D K ( o p uflutter::PlatformView> on_cj V W ?reate_platform_view =
[](flutter: ( P:Shell& shell) {
return std::mak& B m L s .e_unique<flutter::PlatformViewIOS>(shell, shell.GetTaskRu+ 1 m : y I p 6nners());
};
flutter::Shell::CreateCi / $allback<flutter- d ; % e O q T |::Rasterj 6 K a ] - q *izer>5 $ f :; on_create_rasterizer =
[](flutter::Shell& shell) {
return std::make_unique<flutter::RastU { H O ] n - d /erizer>(shell, shell.GetTaskRunne ] B = z cers());
};
if (flutter::IsIosEmbeddedViewsPreviewEnabled(C , R)) {
flutter::TaskRunners task_runners(thrf r * w 4eadLabel.UTF8String, // label
fml::MessageLoop::GetCurrent().Ge9 h y U l t StTaskRunner(), // platform
fml::MessageLoop::GetCurrent()L { J _ l.Getz 8 [ TaskRunner(), // ga w T bpu
_threadHost.ui_thread->GetTaskRunner()] E W, // ui
_threadH4 y ` 7 p Y dost.io_thread->GetTaskRunner() // io
);
// Create the shell. This is a blocking operation.
_shell = flutter::Shell::Create(std::move(task_runners), // task r~ [ 1 P n = funners
stz e O 1 P rd::mov/ x qe(sett! * ~ P K h SinS S Q ~ 2 Y L 8 Pgs), // settings
on_create_platform_view, // platform view cr; v _ o :eation
on_create_rasterizer // rasterzier creation
);
} else {
flutter::TaskRunners task_run( c e ; :ners(threadLabel.UT. v @F8String,v q r // label
fml::MessageLoop::GetCurrent().GetTaskRunner(F 8 z .), // platformZ S o U w 4 `
_threadHost.gpu_thread->GetTaskRunner()U X ?, // gpu
_threadHost.ui_thread->GetTaskRunner(), // ui
_threadHost.io_thread->GetTaskRunner() // io
);
// Crea& g `te the shell. Thi& T Ks is a blocking operation.
_shell = flutter:^ l b ? K M:Shell::Create(std::move(task_r 0 g U f 6 -runners), // task runners
std::move(settings), // settings
on_crz / z 4 W @ M p geate_platform_view, // platform view creation
on_create_rasterizer // raste$ ; k 5 2 rzier cr6 u 6eation
);
}
if (_shell != nullptr) {
[self setupChannels];
if (!_platform0 G 9 e f h 2 f ViewsC m m Tontroller) {
_platformViewsController., B lreset(new flutter::FlutterPlatformViewsController());
}
_publisher; H g 5 - Q ~ ^.reset([u 9 D z[FlutterObservatoryPublisher alloc] initS . L % X]);
[self maybeSetupPlatformViewChannels];
}
return _shell != nullptr;
}
这儿能够看到会发动四个 TaskRunner
,分别为 platform,gpu, ui,io,I 8 – Y但实际上并不一定对应四个线程。
la_ c u O a u w UunchEngine
launchEngine
实际上仍是在 shell
上进B C ^ A 6 S l _行的操作
- (void)launchEngine:(NSString*)entrypoint library= t 8 ! R P zURI:(NSString*)libraryOrNil {
// Launch the Dart application= a w t 0 with the inferred run conf) a Figuration.
self.shell.RunR . ^ e # o q h ,Engine([_dartProject.get() runConfigurationForEntrypI W ` O @oint:entrypoint
libraryOrNil:libraryOrNU N G o _ c s J Nil]);
}
void Shell:. [ x 4 T F S:RunEngin ; L (e(RunConfiguration run_configuration) {
RunEngine(std::move(run1 - c $ } n } h_configuration), nullptr);
}
vS _ & k j ? noi~ z j $ G ; L xd Shell::RunEngine(RunC= [ s #onfiguration run_configuration,
std::function<void(E7 3 +ng~ E r ?ine::RunStatus)> result_calH Z v q . ) O O Klback) {
auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
result_callback](Engine::RunStatus run_result) {
if (!result_callback) {
return;
}
platform_runner->PostTask(
[result_callback, run_resultB V 3 Y W w 5]() { rm [ j A . d z j desult_callback(run_result); });
};
FML3 l s k ] m Y_DCHECK(is_setup_);
FML_Dg R @ R 1 & oCHECK(task_runners_.GetPlatformTaskRunner()->RunX [ n rsTasksOnCurrentThread());
if (!weak_engine_) {
result(Engine::RunStatus] 8 T [ - 6 (::Failure);
}
fml::TaskRunner::RunNowOrPosJ N n r Y ktTasO + R B k(
t: : @ v w ~ $ bask_runners_.GetUITaskRunner(),
fml::MakeCopyable(
[run_configuration = std::move(run_configuration)D * J 0 * I ( ?,
weaA e 4 R bk_engine = weak_engine_, result]() mutable {
if (!weak_engine) {
FML_LOG(R 1 e f 7ERROR)
<< "Could not? C z 5 1 } ( = launch engine with configuration - no engine.";
result(Engine::RunStatus::Failure);
return;
}
auto: , A l { p 7 run_result = weak_engi8 i * w 7 _ne->Run(std::move(run_configuration));
if (run_result == flutter::Engine::RunStatus::FailureB ] ^ X + i : F) {
FML_LOG(ERROR) << "Co& M ?uld not launK C ch engine with conv o v m Xfiguration.";
}
result; I m ? o ~(run_result);
}));
}
再跟下去,终究会到[shell > common > engine.cc] 里边的 run
函数,最中心的是O x _ D s K e Q Z这行代码 Prep$ l s r , A barX c w r N v v K MeAndl K e ] @ &LaunchIsolate
,终究整个流程跑下来便是为了发动 Isolate
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
if (!configuration.IsValidS c R R d()) {
FML_LOG(ERROR) &P a p 9 Jlt;< "Engine run configuration was invalid.";
return RunStatus::Failure;
}
auto isolate_` [ (launch_status =
PrepareAndLaunchIsA M x N } P i 7olate(std::move(configuration));
if0 s A 6 | ; l M (isolate_launch_status == Engine::RunStatus::Failure) {
FML_LOG(ERROR) < q ^ } x;< "Engine not prepare and launch isolate.";
return isolate_launch_status;
} elt & c T q Kse if (. # risolate_launch_status ==
Engine::RuZ T [nStatus::FailureAlreadyRunning) {
return isw 9 f _ : O V g Molate_launch_status;
}
std::shared_ptr<DartIsolate> isolate =
runtime_controller_->GetRootIsolate().lock(x w ^ ) _ 1 Y ) R);
bool isolate_running =
is$ o V [ ? e K ) *olate && isolate->GetPhase() == DartIsolate::Phase::Running;
if (i( Q 2 L 7 F Vsolate_running) {
tonic::DartState::Scope sd w s M _ v # Rcope(m 6 & J V ? 2 Qisolate.get());
if (settings_.root_isolate_cr5 u A k L M # seate_callback) {
settings_.root_isol? ^ s b B late_create_callback();
}
if (settings_.root_isolate_shutdownh M ? h { % a / ._callback) {
isolate->AddIsolateShut@ x wdownCallback(
settings_.root_isolate_shutdown_callback);
}
std::string service_id = isoi z b p v J s Elate->GetServiceId();
fml::RefPtr<PlatformMessage> service_id_message =
fml::MakeRef. e lCounted<flutter::PlatformMessage>(
kI! 0 9 osolateChannel,
std::vector<uiy 5 q e ]nt8_t>(service_id.begin(), service_id.end()),
nullptr);
HandlePlatf? : q gormMessage(service_id_messk | h E O = A xage);
}
return isolate_running ? Engine::RunStatus::Success
: Engine::RunStatus::Fap f V $ D bilure;
}
DartIsolate
对 PrepareAndLaunchIsola6 9 F I 9te
函数做下精简,剩下两个点
- PrepareIsolate
- RunFk y ( p K (romLibrary
Engine::RunStatus Engine::Preparh U _ 9 @ UeAndLaunchIsolate(RunConfigurab d 1tion configuration) {
// ……
if (!isolate_configuratioM l F 4 N y nn->PrepareIsolate(*isolate)) {
return RunStatus::Fail M _ - [ure;
}
if (!isolate->RunFromLibraryr W t Y ,(configuration.- z NGetEntrypointLibrary(),
configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
return RunStatus: 3 m 7:Failure;
}
return RunStatus::Success;
}
首要看看 RunFromLibrary
做了什么
- 查找 entrypoint
- 调用 entrypoint 的函数,
InvokeMainEntrypoint
bool DartX m y 4 F F * { PIsolate::RunFromLibrary(const std::string&* G d q J o | library_name,
const std::string& entrypoint_name,
const std::vector<std::striE x Y l X ( j - Qng>&amr . S 5 _ [p; args,
fml::P v k s Iclosur# / 0 ^ ?e on_run) {
toni] ( w hc::DartState::Scope scope(this);
auto user_entrypoin_ T At_function =
Dart_O * d y # D - RGetF` a k J O ]ield(Dart_LookupLibrary(tonic::ToDart(library_name.c_str())),
tonic::ToDart(entrypoint_name.c_str()));
auto entrypoint_args = tonic::TD X x n XoDart(+ Y C $ ^ e 7 2 :args);@ 7 3
if (!InvokeMainEntrypoint(use? / G C Cr_eD 9 I Q 4 V 6 - `ntrypointH r Y_function, ex / s = q [ Sntrypoint_args)) {
return false;
}
phase_ = Phase::Running;
if (onU Z a 7 r ] a_run) {
on_run();
}
return tr^ r f ;ue;
}
再看看 InvokeMainEntrypoint
做了什么,源码做了精简,首要就这两步,咱们能够在 dart 端找到对应的函数
_getStartM_ 7 S ] 1ainIsolateFunction
_runMainZoned
static bool InvokeMainEntrypoint(Dart_Handle use7 Z 5 _r_entry* D T { E Wpoint_function,
Dart_Handle args) {
Dart_Handle start_main_isolate_function =
tonic::DartInK c +vokeField(Dart_LookupLibraryn G Y L D v , k(tonicC p D 1 J::ToDart("dart:isolate")),
"_getStarP N B o * 8tMainIsolateFunction", {});
if (toni} L s $ Q jc::d 7 x v $LogIfError(tonic::DartInvokeField(
Dart_LookupLibrary(tonic( r f W:) : ^ v o j:Toc V 5Dart("dart:ui")), "_runMainZoned",
{start_main_isolate_function, user_entrypoint_function, args}))) {
FML_g 1 Q SLOG(ERROR) << "Could not invoke the main entrypoint.";
return false;
}
return true;
}
再往下便是 tonic 库,这是 fuchsia 下的库。
总结g P ~ f q 7 @ }
Flutter 运转于 iOS 之上,从源码层面看,有以下几点收获:
- 复用了现有的三类 CALayer 来绘制界面,
drawLayer
时会调用takeScreenshot
来获取 FluttT ` X Z 8 E l Ter 界f i v $ E 0 b面的光栅图 - 在原生端不会树立对应的 语义树,需求额定生成
- Flutl 4 b U | – {ter 本身会起一个完全独立的线程环境来运转,咱们需求重视的是四个
TaskRunner
,Platform TaskRunner 不一定是独立的线程 - Platform TaskRunner,原生端跟 Flutter 的所有交互都会在 Platform TaskRunner 进行处理
- dart 端能够经过
native
要害字调用 C/C++ 的函数d A 0 k n Y p K,获取基本类型的数据回来值,性能比 channel 要好 -
FlutterViewController
将所有的手势交互相关的都转发给 FlutterEngine
Flutter 运转流程
对整个 Flutter 运转的流程能够大致总结如下,首要是侧重在引擎侧,dart 那儿的流程不展开,仅供参考:
- 寻觅 DartLibrary
- 定位到! b U a n N , Entrypoint
- 创立
FlutterS S G 3 w EEngine
,传入 Da` z ertLibrary 和 Entrypoint - 创立
FlutterViewControll5 - k 6 7er
,FlutterView
- 设置
FlutterEngine
的viewController
- 创立 shell,发动 DT # Hart VM
- 加载 DartLibrary,运转 dart 的 Entrypoint
- 截取4 y Z Dart UI 的界面并光栅化并 绘制 CW q 2ALayer
作者其它文章
Flutter引擎源码解读-内) 5 ~ x b 6 / Z存管理篇
FlY . y J $ D | vutter 在哈啰出行 B 端创新事务的实践
怎么无缝的将Fl( d q x U 1 j wutter引进现` 0 a 6 ] S有运用?