Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
FlutterEngine.mm
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <UIKit/UIKit.h>
6#include "common/settings.h"
7#define FML_USED_ON_EMBEDDER
8
10
11#include <memory>
12
24#import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
27#import "flutter/shell/platform/darwin/ios/InternalFlutterSwift/InternalFlutterSwift.h"
46
48
49/// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities
50/// Using iOS platform thread API to configure thread priority
52 // set thread name
54
55 // set thread priority
56 switch (config.priority) {
58 pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
59 [[NSThread currentThread] setThreadPriority:0];
60 break;
61 }
63 pthread_set_qos_class_self_np(QOS_CLASS_DEFAULT, 0);
64 [[NSThread currentThread] setThreadPriority:0.5];
65 break;
66 }
69 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
70 [[NSThread currentThread] setThreadPriority:1.0];
71 sched_param param;
72 int policy;
73 pthread_t thread = pthread_self();
74 if (!pthread_getschedparam(thread, &policy, &param)) {
75 param.sched_priority = 50;
76 pthread_setschedparam(thread, policy, &param);
77 }
78 break;
79 }
80 }
81}
82
83#pragma mark - Public exported constants
84
85NSString* const FlutterDefaultDartEntrypoint = nil;
86NSString* const FlutterDefaultInitialRoute = nil;
87
88#pragma mark - Internal constants
89
90NSString* const kFlutterKeyDataChannel = @"flutter/keydata";
91static constexpr int kNumProfilerSamplesPerSec = 5;
92NSString* const kFlutterApplicationRegistrarKey = @"io.flutter.flutter.application_registrar";
93
95
96@property(nonatomic, weak) FlutterEngine* flutterEngine;
97@property(nonatomic, readonly) NSString* key;
98
99- (instancetype)initWithKey:(NSString*)key flutterEngine:(FlutterEngine*)flutterEngine;
100
101@end
102
104 : FlutterEngineBaseRegistrar <FlutterApplicationRegistrar>
105@end
106
108@end
109
110@interface FlutterEngine () <FlutterIndirectScribbleDelegate,
111 FlutterUndoManagerDelegate,
112 FlutterTextInputDelegate,
113 FlutterBinaryMessenger,
114 FlutterTextureRegistry>
115
116#pragma mark - Properties
117
118@property(nonatomic, readonly) FlutterDartProject* dartProject;
119@property(nonatomic, readonly, copy) NSString* labelPrefix;
120@property(nonatomic, readonly, assign) BOOL allowHeadlessExecution;
121@property(nonatomic, readonly, assign) BOOL restorationEnabled;
122
123@property(nonatomic, strong) FlutterPlatformViewsController* platformViewsController;
124@property(nonatomic, strong) FlutterEnginePluginSceneLifeCycleDelegate* sceneLifeCycleDelegate;
125
126// Maintains a dictionary of plugin names that have registered with the engine. Used by
127// FlutterEnginePluginRegistrar to implement a FlutterPluginRegistrar.
128@property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
129@property(nonatomic, readonly)
130 NSMutableDictionary<NSString*, FlutterEngineBaseRegistrar*>* registrars;
131
132@property(nonatomic, readwrite, copy) NSString* isolateId;
133@property(nonatomic, copy) NSString* initialRoute;
134@property(nonatomic, strong) id<NSObject> flutterViewControllerWillDeallocObserver;
135@property(nonatomic, strong) FlutterDartVMServicePublisher* publisher;
136@property(nonatomic, strong) FlutterConnectionCollection* connections;
137@property(nonatomic, assign) int64_t nextTextureId;
138
139#pragma mark - Channel properties
140
141@property(nonatomic, strong) FlutterPlatformPlugin* platformPlugin;
142@property(nonatomic, strong) FlutterTextInputPlugin* textInputPlugin;
143@property(nonatomic, strong) FlutterUndoManagerPlugin* undoManagerPlugin;
144@property(nonatomic, strong) FlutterSpellCheckPlugin* spellCheckPlugin;
145@property(nonatomic, strong) FlutterRestorationPlugin* restorationPlugin;
146@property(nonatomic, strong) FlutterMethodChannel* localizationChannel;
147@property(nonatomic, strong) FlutterMethodChannel* navigationChannel;
148@property(nonatomic, strong) FlutterMethodChannel* restorationChannel;
149@property(nonatomic, strong) FlutterMethodChannel* platformChannel;
150// This channel only sends status bar related events to the framework thus has
151// no handlers.
152@property(nonatomic, strong) FlutterMethodChannel* statusBarChannel;
153@property(nonatomic, strong) FlutterMethodChannel* platformViewsChannel;
154@property(nonatomic, strong) FlutterMethodChannel* textInputChannel;
155@property(nonatomic, strong) FlutterMethodChannel* undoManagerChannel;
156@property(nonatomic, strong) FlutterMethodChannel* scribbleChannel;
157@property(nonatomic, strong) FlutterMethodChannel* spellCheckChannel;
158@property(nonatomic, strong) FlutterBasicMessageChannel* lifecycleChannel;
159@property(nonatomic, strong) FlutterBasicMessageChannel* systemChannel;
160@property(nonatomic, strong) FlutterBasicMessageChannel* settingsChannel;
161@property(nonatomic, strong) FlutterBasicMessageChannel* keyEventChannel;
162@property(nonatomic, strong) FlutterMethodChannel* screenshotChannel;
163
164#pragma mark - Embedder API properties
165
166@property(nonatomic, assign) BOOL enableEmbedderAPI;
167// Function pointers for interacting with the embedder.h API.
168@property(nonatomic) FlutterEngineProcTable& embedderAPI;
169
170@end
171
173 FlutterEngine* _engine;
174 NSObject<FlutterApplicationRegistrar>* _appRegistrar;
175}
176
177- (instancetype)initWithEngine:(FlutterEngine*)engine {
178 self = [super init];
179 if (self) {
180 _engine = engine;
181 _appRegistrar = [engine registrarForApplication:kFlutterApplicationRegistrarKey];
182 }
183 return self;
184}
185
186- (NSObject<FlutterPluginRegistry>*)pluginRegistry {
187 return _engine;
188}
189
190- (NSObject<FlutterApplicationRegistrar>*)applicationRegistrar {
191 return _appRegistrar;
192}
193@end
194
195@implementation FlutterEngine {
196 std::shared_ptr<flutter::ThreadHost> _threadHost;
197 std::unique_ptr<flutter::Shell> _shell;
198
200 std::shared_ptr<flutter::SamplingProfiler> _profiler;
201
204
208}
209
210- (int64_t)engineIdentifier {
211 return reinterpret_cast<int64_t>((__bridge void*)self);
212}
213
214- (instancetype)init {
215 return [self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
216}
217
218- (instancetype)initWithName:(NSString*)labelPrefix {
219 return [self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
220}
221
222- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
223 return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
224}
225
226- (instancetype)initWithName:(NSString*)labelPrefix
227 project:(FlutterDartProject*)project
228 allowHeadlessExecution:(BOOL)allowHeadlessExecution {
229 return [self initWithName:labelPrefix
230 project:project
231 allowHeadlessExecution:allowHeadlessExecution
232 restorationEnabled:NO];
233}
234
235- (instancetype)initWithName:(NSString*)labelPrefix
236 project:(FlutterDartProject*)project
237 allowHeadlessExecution:(BOOL)allowHeadlessExecution
238 restorationEnabled:(BOOL)restorationEnabled {
239 self = [super init];
240 NSAssert(self, @"Super init cannot be nil");
241 NSAssert(labelPrefix, @"labelPrefix is required");
242
243 _restorationEnabled = restorationEnabled;
244 _allowHeadlessExecution = allowHeadlessExecution;
245 _labelPrefix = [labelPrefix copy];
246 _dartProject = project ?: [[FlutterDartProject alloc] init];
247
248 _enableEmbedderAPI = _dartProject.settings.enable_embedder_api;
249 if (_enableEmbedderAPI) {
250 NSLog(@"============== iOS: enable_embedder_api is on ==============");
251 _embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
252 FlutterEngineGetProcAddresses(&_embedderAPI);
253 }
254
255 if (!EnableTracingIfNecessary(_dartProject.settings)) {
256 NSLog(
257 @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
258 @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
259 @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
260 @"profile and release mode apps can be launched from the home screen.");
261 return nil;
262 }
263
264 _pluginPublications = [[NSMutableDictionary alloc] init];
265 _registrars = [[NSMutableDictionary alloc] init];
266 [self recreatePlatformViewsController];
267 _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
268 _textureRegistry = [[FlutterTextureRegistryRelay alloc] initWithParent:self];
269 _connections = [[FlutterConnectionCollection alloc] init];
270
271 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
272 [center addObserver:self
273 selector:@selector(onMemoryWarning:)
274 name:UIApplicationDidReceiveMemoryWarningNotification
275 object:nil];
276
277 [self setUpLifecycleNotifications:center];
278
279 [center addObserver:self
280 selector:@selector(onLocaleUpdated:)
281 name:NSCurrentLocaleDidChangeNotification
282 object:nil];
283
284 self.sceneLifeCycleDelegate = [[FlutterEnginePluginSceneLifeCycleDelegate alloc] init];
285
286 return self;
287}
288
289+ (FlutterEngine*)engineForIdentifier:(int64_t)identifier {
290 NSAssert([[NSThread currentThread] isMainThread], @"Must be called on the main thread.");
291 return (__bridge FlutterEngine*)reinterpret_cast<void*>(identifier);
292}
293
294- (void)setUpLifecycleNotifications:(NSNotificationCenter*)center {
295 // If the application is not available, use the scene for lifecycle notifications if available.
296 [center addObserver:self
297 selector:@selector(sceneWillConnect:)
298 name:UISceneWillConnectNotification
299 object:nil];
301 [center addObserver:self
302 selector:@selector(sceneWillEnterForeground:)
303 name:UISceneWillEnterForegroundNotification
304 object:nil];
305 [center addObserver:self
306 selector:@selector(sceneDidEnterBackground:)
307 name:UISceneDidEnterBackgroundNotification
308 object:nil];
309 return;
310 }
311 [center addObserver:self
312 selector:@selector(applicationWillEnterForeground:)
313 name:UIApplicationWillEnterForegroundNotification
314 object:nil];
315 [center addObserver:self
316 selector:@selector(applicationDidEnterBackground:)
317 name:UIApplicationDidEnterBackgroundNotification
318 object:nil];
319}
320
321- (void)sceneWillConnect:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
322 UIScene* scene = notification.object;
323 if (!FlutterSharedApplication.application.supportsMultipleScenes) {
324 // Since there is only one scene, we can assume that the FlutterEngine is within this scene and
325 // register it to the scene.
326 // The FlutterEngine needs to be registered with the scene when the scene connects in order for
327 // plugins to receive the `scene:willConnectToSession:options` event.
328 // If we want to support multi-window on iPad later, we may need to add a way for deveopers to
329 // register their FlutterEngine to the scene manually during this event.
330 FlutterPluginSceneLifeCycleDelegate* sceneLifeCycleDelegate =
331 [FlutterPluginSceneLifeCycleDelegate fromScene:scene];
332 if (sceneLifeCycleDelegate != nil) {
333 return [sceneLifeCycleDelegate engine:self receivedConnectNotificationFor:scene];
334 }
335 }
336}
337
338- (void)recreatePlatformViewsController {
339 _renderingApi = flutter::GetRenderingAPIForProcess(/*force_software=*/false);
340 _platformViewsController = [[FlutterPlatformViewsController alloc] init];
341}
342
343- (flutter::IOSRenderingAPI)platformViewsRenderingAPI {
344 return _renderingApi;
345}
346
347- (void)dealloc {
348 /// Notify plugins of dealloc. This should happen first in dealloc since the
349 /// plugins may be talking to things like the binaryMessenger.
350 [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
351 if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
352 FlutterEngineBaseRegistrar* registrar = self.registrars[key];
353 if ([registrar conformsToProtocol:@protocol(FlutterPluginRegistrar)]) {
354 [object detachFromEngineForRegistrar:((id<FlutterPluginRegistrar>)registrar)];
355 }
356 }
357 }];
358
359 // nil out weak references.
360 // TODO(cbracken): https://github.com/flutter/flutter/issues/156222
361 // Ensure that FlutterEnginePluginRegistrar is using weak pointers, then eliminate this code.
362 [_registrars enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineBaseRegistrar* registrar,
363 BOOL* stop) {
364 registrar.flutterEngine = nil;
365 }];
366
369
370 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
371 if (_flutterViewControllerWillDeallocObserver) {
372 [center removeObserver:_flutterViewControllerWillDeallocObserver];
373 }
374 [center removeObserver:self];
375}
376
377- (flutter::Shell&)shell {
379 return *_shell;
380}
381
382- (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics {
383 if (!self.platformView) {
384 return;
385 }
386 self.platformView->SetViewportMetrics(flutter::kFlutterImplicitViewId, viewportMetrics);
387}
388
389- (void)dispatchPointerDataPacket:(std::unique_ptr<flutter::PointerDataPacket>)packet {
390 if (!self.platformView) {
391 return;
392 }
393 self.platformView->DispatchPointerDataPacket(std::move(packet));
394}
395
396- (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(flutter::PointData)location
397 viewId:(uint64_t)viewId {
398 if (!self.platformView) {
399 return NO;
400 }
401 return self.platformView->HitTest(viewId, location).has_platform_view;
402}
403
404- (void)installFirstFrameCallback:(void (^)(void))block {
405 if (!self.platformView) {
406 return;
407 }
408
409 __weak FlutterEngine* weakSelf = self;
410 self.platformView->SetNextFrameCallback([weakSelf, block] {
411 FlutterEngine* strongSelf = weakSelf;
412 if (!strongSelf) {
413 return;
414 }
415 FML_DCHECK(strongSelf.platformTaskRunner);
416 FML_DCHECK(strongSelf.rasterTaskRunner);
417 FML_DCHECK([strongSelf.rasterTaskRunner runsTasksOnCurrentThread]);
418 // Get callback on raster thread and jump back to platform thread.
419 [strongSelf.platformTaskRunner postTask:^{
420 block();
421 }];
422 });
423}
424
425- (void)enableSemantics:(BOOL)enabled withFlags:(int64_t)flags {
426 if (!self.platformView) {
427 return;
428 }
429 self.platformView->SetSemanticsEnabled(enabled);
430 self.platformView->SetAccessibilityFeatures(flags);
431}
432
433- (void)notifyViewCreated {
434 if (!self.platformView) {
435 return;
436 }
437 self.platformView->NotifyCreated();
438}
439
440- (void)notifyViewDestroyed {
441 if (!self.platformView) {
442 return;
443 }
444 self.platformView->NotifyDestroyed();
445}
446
447- (flutter::PlatformViewIOS*)platformView {
448 if (!_shell) {
449 return nullptr;
450 }
451 return static_cast<flutter::PlatformViewIOS*>(_shell->GetPlatformView().get());
452}
453
454- (FlutterFMLTaskRunner*)platformTaskRunner {
456}
457
458- (FlutterFMLTaskRunner*)uiTaskRunner {
460}
461
462- (FlutterFMLTaskRunner*)rasterTaskRunner {
464}
465
466- (void)sendKeyEvent:(const FlutterKeyEvent&)event
467 callback:(FlutterKeyEventCallback)callback
468 userData:(void*)userData API_AVAILABLE(ios(13.4)) {
469 if (@available(iOS 13.4, *)) {
470 } else {
471 return;
472 }
473 if (!self.platformView) {
474 return;
475 }
476 const char* character = event.character;
477
478 flutter::KeyData key_data;
479 key_data.Clear();
480 key_data.timestamp = (uint64_t)event.timestamp;
481 switch (event.type) {
484 break;
487 break;
490 break;
491 }
492 key_data.physical = event.physical;
493 key_data.logical = event.logical;
494 key_data.synthesized = event.synthesized;
495
496 auto packet = std::make_unique<flutter::KeyDataPacket>(key_data, character);
497 NSData* message = [NSData dataWithBytes:packet->data().data() length:packet->data().size()];
498
499 auto response = ^(NSData* reply) {
500 if (callback == nullptr) {
501 return;
502 }
503 BOOL handled = FALSE;
504 if (reply.length == 1 && *reinterpret_cast<const uint8_t*>(reply.bytes) == 1) {
505 handled = TRUE;
506 }
507 callback(handled, userData);
508 };
509
510 [self sendOnChannel:kFlutterKeyDataChannel message:message binaryReply:response];
511}
512
513- (void)ensureSemanticsEnabled {
514 if (!self.platformView) {
515 return;
516 }
517 self.platformView->SetSemanticsEnabled(true);
518}
519
520- (void)setViewController:(FlutterViewController*)viewController {
521 FML_DCHECK(self.platformView);
522 _viewController = viewController;
523 self.platformView->SetOwnerViewController(_viewController);
524 [self maybeSetupPlatformViewChannels];
525 [self updateDisplays];
526 self.textInputPlugin.viewController = viewController;
527
528 if (viewController) {
529 __weak __block FlutterEngine* weakSelf = self;
530 self.flutterViewControllerWillDeallocObserver =
531 [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
532 object:viewController
533 queue:[NSOperationQueue mainQueue]
534 usingBlock:^(NSNotification* note) {
535 [weakSelf notifyViewControllerDeallocated];
536 }];
537 } else {
538 self.flutterViewControllerWillDeallocObserver = nil;
539 [self notifyLowMemory];
540 }
541}
542
543- (void)attachView {
544 FML_DCHECK(self.platformView);
545 self.platformView->attachView();
546}
547
548- (void)setFlutterViewControllerWillDeallocObserver:(id<NSObject>)observer {
549 if (observer != _flutterViewControllerWillDeallocObserver) {
550 if (_flutterViewControllerWillDeallocObserver) {
551 [[NSNotificationCenter defaultCenter]
552 removeObserver:_flutterViewControllerWillDeallocObserver];
553 }
554 _flutterViewControllerWillDeallocObserver = observer;
555 }
556}
557
558- (void)notifyViewControllerDeallocated {
559 [self.lifecycleChannel sendMessage:@"AppLifecycleState.detached"];
560 self.textInputPlugin.viewController = nil;
561 if (!self.allowHeadlessExecution) {
562 [self destroyContext];
563 } else if (self.platformView) {
564 self.platformView->SetOwnerViewController({});
565 }
566 [self.textInputPlugin resetViewResponder];
567 _viewController = nil;
568}
569
570- (void)destroyContext {
571 [self resetChannels];
572 self.isolateId = nil;
573 _shell.reset();
574 _profiler.reset();
575 _threadHost.reset();
576 _platformViewsController = nil;
580}
581
582- (NSURL*)vmServiceUrl {
583 return self.publisher.url;
584}
585
586- (void)resetChannels {
587 self.localizationChannel = nil;
588 self.navigationChannel = nil;
589 self.restorationChannel = nil;
590 self.platformChannel = nil;
591 self.statusBarChannel = nil;
592 self.platformViewsChannel = nil;
593 self.textInputChannel = nil;
594 self.undoManagerChannel = nil;
595 self.scribbleChannel = nil;
596 self.lifecycleChannel = nil;
597 self.systemChannel = nil;
598 self.settingsChannel = nil;
599 self.keyEventChannel = nil;
600 self.spellCheckChannel = nil;
601}
602
603- (void)startProfiler {
604 FML_DCHECK(!_threadHost->name_prefix.empty());
605 _profiler = std::make_shared<flutter::SamplingProfiler>(
606 _threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
607 []() {
608 flutter::ProfilerMetricsIOS profiler_metrics;
609 return profiler_metrics.GenerateSample();
610 },
612 _profiler->Start();
613}
614
615// If you add a channel, be sure to also update `resetChannels`.
616// Channels get a reference to the engine, and therefore need manual
617// cleanup for proper collection.
618- (void)setUpChannels {
619 // This will be invoked once the shell is done setting up and the isolate ID
620 // for the UI isolate is available.
621 __weak FlutterEngine* weakSelf = self;
622 [_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate"
623 binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
624 if (weakSelf) {
625 weakSelf.isolateId =
626 [[FlutterStringCodec sharedInstance] decode:message];
627 }
628 }];
629
631 [[FlutterMethodChannel alloc] initWithName:@"flutter/localization"
632 binaryMessenger:self.binaryMessenger
633 codec:[FlutterJSONMethodCodec sharedInstance]];
634
635 self.navigationChannel =
636 [[FlutterMethodChannel alloc] initWithName:@"flutter/navigation"
637 binaryMessenger:self.binaryMessenger
638 codec:[FlutterJSONMethodCodec sharedInstance]];
639
640 if ([_initialRoute length] > 0) {
641 // Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
642 [self.navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
643 _initialRoute = nil;
644 }
645
646 self.restorationChannel =
647 [[FlutterMethodChannel alloc] initWithName:@"flutter/restoration"
648 binaryMessenger:self.binaryMessenger
649 codec:[FlutterStandardMethodCodec sharedInstance]];
650
651 self.platformChannel =
652 [[FlutterMethodChannel alloc] initWithName:@"flutter/platform"
653 binaryMessenger:self.binaryMessenger
654 codec:[FlutterJSONMethodCodec sharedInstance]];
655
656 self.statusBarChannel =
657 [[FlutterMethodChannel alloc] initWithName:@"flutter/status_bar"
658 binaryMessenger:self.binaryMessenger
659 codec:[FlutterJSONMethodCodec sharedInstance]];
660 [self.statusBarChannel resizeChannelBuffer:0]; // No buffering.
661
662 self.platformViewsChannel =
663 [[FlutterMethodChannel alloc] initWithName:@"flutter/platform_views"
664 binaryMessenger:self.binaryMessenger
665 codec:[FlutterStandardMethodCodec sharedInstance]];
666
667 self.textInputChannel =
668 [[FlutterMethodChannel alloc] initWithName:@"flutter/textinput"
669 binaryMessenger:self.binaryMessenger
670 codec:[FlutterJSONMethodCodec sharedInstance]];
671
672 self.undoManagerChannel =
673 [[FlutterMethodChannel alloc] initWithName:@"flutter/undomanager"
674 binaryMessenger:self.binaryMessenger
675 codec:[FlutterJSONMethodCodec sharedInstance]];
676
677 self.scribbleChannel =
678 [[FlutterMethodChannel alloc] initWithName:@"flutter/scribble"
679 binaryMessenger:self.binaryMessenger
680 codec:[FlutterJSONMethodCodec sharedInstance]];
681
682 self.spellCheckChannel =
683 [[FlutterMethodChannel alloc] initWithName:@"flutter/spellcheck"
684 binaryMessenger:self.binaryMessenger
685 codec:[FlutterStandardMethodCodec sharedInstance]];
686
687 self.lifecycleChannel =
688 [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/lifecycle"
689 binaryMessenger:self.binaryMessenger
691
692 self.systemChannel =
693 [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/system"
694 binaryMessenger:self.binaryMessenger
696
697 self.settingsChannel =
698 [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/settings"
699 binaryMessenger:self.binaryMessenger
701
702 self.keyEventChannel =
703 [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/keyevent"
704 binaryMessenger:self.binaryMessenger
706
707 self.textInputPlugin = [[FlutterTextInputPlugin alloc] initWithDelegate:self];
708 self.textInputPlugin.indirectScribbleDelegate = self;
709 [self.textInputPlugin setUpIndirectScribbleInteraction:self.viewController];
710
711 self.undoManagerPlugin = [[FlutterUndoManagerPlugin alloc] initWithDelegate:self];
712 self.platformPlugin = [[FlutterPlatformPlugin alloc] initWithEngine:self];
713
714 self.restorationPlugin =
715 [[FlutterRestorationPlugin alloc] initWithChannel:self.restorationChannel
716 restorationEnabled:self.restorationEnabled];
717 self.spellCheckPlugin = [[FlutterSpellCheckPlugin alloc] init];
718
719 self.screenshotChannel =
720 [[FlutterMethodChannel alloc] initWithName:@"flutter/screenshot"
721 binaryMessenger:self.binaryMessenger
722 codec:[FlutterStandardMethodCodec sharedInstance]];
723
724 [self.screenshotChannel setMethodCallHandler:^(FlutterMethodCall* _Nonnull call,
725 FlutterResult _Nonnull result) {
726 FlutterEngine* strongSelf = weakSelf;
727 if (!(strongSelf && strongSelf->_shell && strongSelf->_shell->IsSetup())) {
728 return result([FlutterError
729 errorWithCode:@"invalid_state"
730 message:@"Requesting screenshot while engine is not running."
731 details:nil]);
732 }
733 flutter::Rasterizer::Screenshot screenshot =
734 [strongSelf screenshot:flutter::Rasterizer::ScreenshotType::SurfaceData base64Encode:NO];
735 if (!screenshot.data) {
736 return result([FlutterError errorWithCode:@"failure"
737 message:@"Unable to get screenshot."
738 details:nil]);
739 }
740 // TODO(gaaclarke): Find way to eliminate this data copy.
741 NSData* data = [NSData dataWithBytes:screenshot.data->writable_data()
742 length:screenshot.data->size()];
743 NSString* format = [NSString stringWithUTF8String:screenshot.format.c_str()];
744 NSNumber* width = @(screenshot.frame_size.width);
745 NSNumber* height = @(screenshot.frame_size.height);
746 return result(@[ width, height, format ?: [NSNull null], data ]);
747 }];
748}
749
750- (void)maybeSetupPlatformViewChannels {
751 if (_shell && self.shell.IsSetup()) {
752 __weak FlutterEngine* weakSelf = self;
753
754 [self.platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
755 [weakSelf.platformPlugin handleMethodCall:call result:result];
756 }];
757
758 [self.platformViewsChannel
759 setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
760 if (weakSelf) {
761 [weakSelf.platformViewsController onMethodCall:call result:result];
762 }
763 }];
764
765 [self.textInputChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
766 [weakSelf.textInputPlugin handleMethodCall:call result:result];
767 }];
768
769 [self.undoManagerChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
770 [weakSelf.undoManagerPlugin handleMethodCall:call result:result];
771 }];
772
773 [self.spellCheckChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
774 [weakSelf.spellCheckPlugin handleMethodCall:call result:result];
775 }];
776 }
777}
778
779- (flutter::Rasterizer::Screenshot)screenshot:(flutter::Rasterizer::ScreenshotType)type
780 base64Encode:(bool)base64Encode {
781 return self.shell.Screenshot(type, base64Encode);
782}
783
784- (void)launchEngine:(NSString*)entrypoint
785 libraryURI:(NSString*)libraryOrNil
786 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
787 // Launch the Dart application with the inferred run configuration.
788 flutter::RunConfiguration configuration =
789 [self.dartProject runConfigurationForEntrypoint:entrypoint
790 libraryOrNil:libraryOrNil
791 entrypointArgs:entrypointArgs];
792
793 configuration.SetEngineId(self.engineIdentifier);
794 self.shell.RunEngine(std::move(configuration));
795}
796
797- (void)setUpShell:(std::unique_ptr<flutter::Shell>)shell
798 withVMServicePublication:(BOOL)doesVMServicePublication {
799 _shell = std::move(shell);
801 initWithTaskRunner:_shell->GetTaskRunners().GetPlatformTaskRunner()];
803 [[FlutterFMLTaskRunner alloc] initWithTaskRunner:_shell->GetTaskRunners().GetUITaskRunner()];
805 initWithTaskRunner:_shell->GetTaskRunners().GetRasterTaskRunner()];
806
807 [self setUpChannels];
808 [self onLocaleUpdated:nil];
809 [self updateDisplays];
810 self.publisher = [[FlutterDartVMServicePublisher alloc]
811 initWithEnableVMServicePublication:doesVMServicePublication];
812 [self maybeSetupPlatformViewChannels];
813 _shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable
815}
816
817+ (BOOL)isProfilerEnabled {
818 bool profilerEnabled = false;
819#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
820 (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
821 profilerEnabled = true;
822#endif
823 return profilerEnabled;
824}
825
826+ (NSString*)generateThreadLabel:(NSString*)labelPrefix {
827 static size_t s_shellCount = 0;
828 return [NSString stringWithFormat:@"%@.%zu", labelPrefix, ++s_shellCount];
829}
830
831static flutter::ThreadHost MakeThreadHost(NSString* thread_label,
832 const flutter::Settings& settings) {
833 // The current thread will be used as the platform thread. Ensure that the message loop is
834 // initialized.
836
839 threadHostType |= flutter::ThreadHost::Type::kUi;
840 }
841
842 if ([FlutterEngine isProfilerEnabled]) {
843 threadHostType = threadHostType | flutter::ThreadHost::Type::kProfiler;
844 }
845
846 flutter::ThreadHost::ThreadHostConfig host_config(thread_label.UTF8String, threadHostType,
848
849 host_config.ui_config =
851 flutter::ThreadHost::Type::kUi, thread_label.UTF8String),
853 host_config.raster_config =
855 flutter::ThreadHost::Type::kRaster, thread_label.UTF8String),
857
858 host_config.io_config =
860 flutter::ThreadHost::Type::kIo, thread_label.UTF8String),
862
863 return (flutter::ThreadHost){host_config};
864}
865
866static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
867 if (libraryURI) {
868 FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library";
869 settings->advisory_script_entrypoint = entrypoint.UTF8String;
870 settings->advisory_script_uri = libraryURI.UTF8String;
871 } else if (entrypoint) {
872 settings->advisory_script_entrypoint = entrypoint.UTF8String;
873 settings->advisory_script_uri = std::string("main.dart");
874 } else {
875 settings->advisory_script_entrypoint = std::string("main");
876 settings->advisory_script_uri = std::string("main.dart");
877 }
878}
879
880- (BOOL)createShell:(NSString*)entrypoint
881 libraryURI:(NSString*)libraryURI
882 initialRoute:(NSString*)initialRoute {
883 if (_shell != nullptr) {
884 [FlutterLogger logWarning:@"This FlutterEngine was already invoked."];
885 return NO;
886 }
887
888 self.initialRoute = initialRoute;
889
890 auto settings = [self.dartProject settings];
891 if (initialRoute != nil) {
892 self.initialRoute = initialRoute;
893 } else if (settings.route.empty() == false) {
894 self.initialRoute = [NSString stringWithUTF8String:settings.route.c_str()];
895 }
896
897 auto platformData = [self.dartProject defaultPlatformData];
898
899 SetEntryPoint(&settings, entrypoint, libraryURI);
900
901 NSString* threadLabel = [FlutterEngine generateThreadLabel:self.labelPrefix];
902 _threadHost = std::make_shared<flutter::ThreadHost>();
903 *_threadHost = MakeThreadHost(threadLabel, settings);
904
905 __weak FlutterEngine* weakSelf = self;
907 [weakSelf](flutter::Shell& shell) {
908 FlutterEngine* strongSelf = weakSelf;
909 if (!strongSelf) {
910 return std::unique_ptr<flutter::PlatformViewIOS>();
911 }
912 [strongSelf recreatePlatformViewsController];
913 strongSelf.platformViewsController.taskRunner = [[FlutterFMLTaskRunner alloc]
914 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
915 return std::make_unique<flutter::PlatformViewIOS>(
916 shell, strongSelf->_renderingApi, strongSelf.platformViewsController,
917 shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(),
918 shell.GetIsGpuDisabledSyncSwitch());
919 };
920
922 [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
923
925 if (settings.enable_impeller &&
928 } else {
929 ui_runner = _threadHost->ui_thread->GetTaskRunner();
930 }
931 flutter::TaskRunners task_runners(threadLabel.UTF8String, // label
933 _threadHost->raster_thread->GetTaskRunner(), // raster
934 ui_runner, // ui
935 _threadHost->io_thread->GetTaskRunner() // io
936 );
937
938 // Disable GPU if the app or scene is running in the background.
939 self.isGpuDisabled = self.viewController
940 ? self.viewController.stateIsBackground
942 FlutterSharedApplication.application.applicationState ==
943 UIApplicationStateBackground;
944
945 // Create the shell. This is a blocking operation.
946 std::unique_ptr<flutter::Shell> shell = flutter::Shell::Create(
947 /*platform_data=*/platformData,
948 /*task_runners=*/task_runners,
949 /*settings=*/settings,
950 /*on_create_platform_view=*/on_create_platform_view,
951 /*on_create_rasterizer=*/on_create_rasterizer,
952 /*is_gpu_disabled=*/_isGpuDisabled);
953
954 if (shell == nullptr) {
955 NSString* errorMessage = [NSString
956 stringWithFormat:@"Could not start a shell FlutterEngine with entrypoint: %@", entrypoint];
957 [FlutterLogger logError:errorMessage];
958 } else {
959 [self setUpShell:std::move(shell)
960 withVMServicePublication:settings.enable_vm_service_publication];
961 if ([FlutterEngine isProfilerEnabled]) {
962 [self startProfiler];
963 }
964 }
965
966 return _shell != nullptr;
967}
968
969- (BOOL)performImplicitEngineCallback {
970 id appDelegate = FlutterSharedApplication.application.delegate;
971 if ([appDelegate conformsToProtocol:@protocol(FlutterImplicitEngineDelegate)]) {
972 id<FlutterImplicitEngineDelegate> provider = (id<FlutterImplicitEngineDelegate>)appDelegate;
973 [provider didInitializeImplicitFlutterEngine:[[FlutterImplicitEngineBridgeImpl alloc]
974 initWithEngine:self]];
975 return YES;
976 }
977 return NO;
978}
979
980- (void)updateDisplays {
981 if (!_shell) {
982 // Tests may do this.
983 return;
984 }
985 auto vsync_waiter = _shell->GetVsyncWaiter().lock();
986 auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
987 std::vector<std::unique_ptr<flutter::Display>> displays;
988 auto screen_size = UIScreen.mainScreen.nativeBounds.size;
989 auto scale = UIScreen.mainScreen.scale;
990 displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
991 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
992 _shell->OnDisplayUpdates(std::move(displays));
993}
994
995- (BOOL)run {
996 return [self runWithEntrypoint:FlutterDefaultDartEntrypoint
997 libraryURI:nil
998 initialRoute:FlutterDefaultInitialRoute];
999}
1000
1001- (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
1002 return [self runWithEntrypoint:entrypoint
1003 libraryURI:libraryURI
1004 initialRoute:FlutterDefaultInitialRoute];
1005}
1006
1007- (BOOL)runWithEntrypoint:(NSString*)entrypoint {
1008 return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
1009}
1010
1011- (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
1012 return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
1013}
1014
1015- (BOOL)runWithEntrypoint:(NSString*)entrypoint
1016 libraryURI:(NSString*)libraryURI
1017 initialRoute:(NSString*)initialRoute {
1018 return [self runWithEntrypoint:entrypoint
1019 libraryURI:libraryURI
1020 initialRoute:initialRoute
1021 entrypointArgs:nil];
1022}
1023
1024- (BOOL)runWithEntrypoint:(NSString*)entrypoint
1025 libraryURI:(NSString*)libraryURI
1026 initialRoute:(NSString*)initialRoute
1027 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
1028 if ([self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
1029 [self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
1030 }
1031
1032 return _shell != nullptr;
1033}
1034
1035- (void)notifyLowMemory {
1036 if (_shell) {
1037 _shell->NotifyLowMemoryWarning();
1038 }
1039 [self.systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
1040}
1041
1042#pragma mark - Text input delegate
1043
1044- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1045 updateEditingClient:(int)client
1046 withState:(NSDictionary*)state {
1047 [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingState"
1048 arguments:@[ @(client), state ]];
1049}
1050
1051- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1052 updateEditingClient:(int)client
1053 withState:(NSDictionary*)state
1054 withTag:(NSString*)tag {
1055 [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithTag"
1056 arguments:@[ @(client), @{tag : state} ]];
1057}
1058
1059- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1060 updateEditingClient:(int)client
1061 withDelta:(NSDictionary*)delta {
1062 [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1063 arguments:@[ @(client), delta ]];
1064}
1065
1066- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1067 updateFloatingCursor:(FlutterFloatingCursorDragState)state
1068 withClient:(int)client
1069 withPosition:(NSDictionary*)position {
1070 NSString* stateString;
1071 switch (state) {
1072 case FlutterFloatingCursorDragStateStart:
1073 stateString = @"FloatingCursorDragState.start";
1074 break;
1075 case FlutterFloatingCursorDragStateUpdate:
1076 stateString = @"FloatingCursorDragState.update";
1077 break;
1078 case FlutterFloatingCursorDragStateEnd:
1079 stateString = @"FloatingCursorDragState.end";
1080 break;
1081 }
1082 [self.textInputChannel invokeMethod:@"TextInputClient.updateFloatingCursor"
1083 arguments:@[ @(client), stateString, position ]];
1084}
1085
1086- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1087 performAction:(FlutterTextInputAction)action
1088 withClient:(int)client {
1089 NSString* actionString;
1090 switch (action) {
1091 case FlutterTextInputActionUnspecified:
1092 // Where did the term "unspecified" come from? iOS has a "default" and Android
1093 // has "unspecified." These 2 terms seem to mean the same thing but we need
1094 // to pick just one. "unspecified" was chosen because "default" is often a
1095 // reserved word in languages with switch statements (dart, java, etc).
1096 actionString = @"TextInputAction.unspecified";
1097 break;
1098 case FlutterTextInputActionDone:
1099 actionString = @"TextInputAction.done";
1100 break;
1101 case FlutterTextInputActionGo:
1102 actionString = @"TextInputAction.go";
1103 break;
1104 case FlutterTextInputActionSend:
1105 actionString = @"TextInputAction.send";
1106 break;
1107 case FlutterTextInputActionSearch:
1108 actionString = @"TextInputAction.search";
1109 break;
1110 case FlutterTextInputActionNext:
1111 actionString = @"TextInputAction.next";
1112 break;
1113 case FlutterTextInputActionContinue:
1114 actionString = @"TextInputAction.continueAction";
1115 break;
1116 case FlutterTextInputActionJoin:
1117 actionString = @"TextInputAction.join";
1118 break;
1119 case FlutterTextInputActionRoute:
1120 actionString = @"TextInputAction.route";
1121 break;
1122 case FlutterTextInputActionEmergencyCall:
1123 actionString = @"TextInputAction.emergencyCall";
1124 break;
1125 case FlutterTextInputActionNewline:
1126 actionString = @"TextInputAction.newline";
1127 break;
1128 }
1129 [self.textInputChannel invokeMethod:@"TextInputClient.performAction"
1130 arguments:@[ @(client), actionString ]];
1131}
1132
1133- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1134 showAutocorrectionPromptRectForStart:(NSUInteger)start
1135 end:(NSUInteger)end
1136 withClient:(int)client {
1137 [self.textInputChannel invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1138 arguments:@[ @(client), @(start), @(end) ]];
1139}
1140
1141- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1142 willDismissEditMenuWithTextInputClient:(int)client {
1143 [self.platformChannel invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1144 arguments:@[ @(client) ]];
1145}
1146
1147- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1148 shareSelectedText:(NSString*)selectedText {
1149 [self.platformPlugin showShareViewController:selectedText];
1150}
1151
1152- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1153 searchWebWithSelectedText:(NSString*)selectedText {
1154 [self.platformPlugin searchWeb:selectedText];
1155}
1156
1157- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1158 lookUpSelectedText:(NSString*)selectedText {
1159 [self.platformPlugin showLookUpViewController:selectedText];
1160}
1161
1162- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1163 performContextMenuCustomActionWithActionID:(NSString*)actionID
1164 textInputClient:(int)client {
1165 [self.platformChannel invokeMethod:@"ContextMenu.onPerformCustomAction"
1166 arguments:@[ @(client), actionID ]];
1167}
1168
1169#pragma mark - FlutterViewEngineDelegate
1170
1171- (void)flutterTextInputView:(FlutterTextInputView*)textInputView showToolbar:(int)client {
1172 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1173 // the framework has finished transitioning to the Scribble channel.
1174 // https://github.com/flutter/flutter/pull/115296
1175 [self.textInputChannel invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1176}
1177
1178- (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1179 focusElement:(UIScribbleElementIdentifier)elementIdentifier
1180 atPoint:(CGPoint)referencePoint
1181 result:(FlutterResult)callback {
1182 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1183 // the framework has finished transitioning to the Scribble channel.
1184 // https://github.com/flutter/flutter/pull/115296
1185 [self.textInputChannel
1186 invokeMethod:@"TextInputClient.focusElement"
1187 arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1188 result:callback];
1189}
1190
1191- (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
1192 requestElementsInRect:(CGRect)rect
1193 result:(FlutterResult)callback {
1194 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1195 // the framework has finished transitioning to the Scribble channel.
1196 // https://github.com/flutter/flutter/pull/115296
1197 [self.textInputChannel
1198 invokeMethod:@"TextInputClient.requestElementsInRect"
1199 arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1200 result:callback];
1201}
1202
1203- (void)flutterTextInputViewScribbleInteractionBegan:(FlutterTextInputView*)textInputView {
1204 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1205 // the framework has finished transitioning to the Scribble channel.
1206 // https://github.com/flutter/flutter/pull/115296
1207 [self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1208}
1209
1210- (void)flutterTextInputViewScribbleInteractionFinished:(FlutterTextInputView*)textInputView {
1211 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1212 // the framework has finished transitioning to the Scribble channel.
1213 // https://github.com/flutter/flutter/pull/115296
1214 [self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionFinished" arguments:nil];
1215}
1216
1217- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1218 insertTextPlaceholderWithSize:(CGSize)size
1219 withClient:(int)client {
1220 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1221 // the framework has finished transitioning to the Scribble channel.
1222 // https://github.com/flutter/flutter/pull/115296
1223 [self.textInputChannel invokeMethod:@"TextInputClient.insertTextPlaceholder"
1224 arguments:@[ @(client), @(size.width), @(size.height) ]];
1225}
1226
1227- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1228 removeTextPlaceholder:(int)client {
1229 // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
1230 // the framework has finished transitioning to the Scribble channel.
1231 // https://github.com/flutter/flutter/pull/115296
1232 [self.textInputChannel invokeMethod:@"TextInputClient.removeTextPlaceholder"
1233 arguments:@[ @(client) ]];
1234}
1235
1236- (void)flutterTextInputView:(FlutterTextInputView*)textInputView
1237 didResignFirstResponderWithTextInputClient:(int)client {
1238 // When flutter text input view resign first responder, send a message to
1239 // framework to ensure the focus state is correct. This is useful when close
1240 // keyboard from platform side.
1241 [self.textInputChannel invokeMethod:@"TextInputClient.onConnectionClosed"
1242 arguments:@[ @(client) ]];
1243
1244 // Platform view's first responder detection logic:
1245 //
1246 // All text input widgets (e.g. EditableText) are backed by a dummy UITextInput view
1247 // in the TextInputPlugin. When this dummy UITextInput view resigns first responder,
1248 // check if any platform view becomes first responder. If any platform view becomes
1249 // first responder, send a "viewFocused" channel message to inform the framework to un-focus
1250 // the previously focused text input.
1251 //
1252 // Caveat:
1253 // 1. This detection logic does not cover the scenario when a platform view becomes
1254 // first responder without any flutter text input resigning its first responder status
1255 // (e.g. user tapping on platform view first). For now it works fine because the TextInputPlugin
1256 // does not track the focused platform view id (which is different from Android implementation).
1257 //
1258 // 2. This detection logic assumes that all text input widgets are backed by a dummy
1259 // UITextInput view in the TextInputPlugin, which may not hold true in the future.
1260
1261 // Have to check in the next run loop, because iOS requests the previous first responder to
1262 // resign before requesting the next view to become first responder.
1263 dispatch_async(dispatch_get_main_queue(), ^(void) {
1264 long platform_view_id = [self.platformViewsController firstResponderPlatformViewId];
1265 if (platform_view_id == -1) {
1266 return;
1267 }
1268
1269 [self.platformViewsChannel invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1270 });
1271}
1272
1273#pragma mark - Undo Manager Delegate
1274
1275- (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1276 NSString* action = (direction == FlutterUndoRedoDirectionUndo) ? @"undo" : @"redo";
1277 [self.undoManagerChannel invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1278}
1279
1280- (UIView<UITextInput>*)activeTextInputView {
1281 return [[self textInputPlugin] textInputView];
1282}
1283
1284- (NSUndoManager*)undoManager {
1285 return self.viewController.undoManager;
1286}
1287
1288#pragma mark - Screenshot Delegate
1289
1290- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
1291 asBase64Encoded:(BOOL)base64Encode {
1292 FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
1293 return _shell->Screenshot(type, base64Encode);
1294}
1295
1296- (void)flutterViewAccessibilityDidCall {
1297 if (self.viewController.view.accessibilityElements == nil) {
1298 [self ensureSemanticsEnabled];
1299 }
1300}
1301
1302- (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
1303 return _binaryMessenger;
1304}
1305
1306- (NSObject<FlutterTextureRegistry>*)textureRegistry {
1307 return _textureRegistry;
1308}
1309
1310// For test only. Ideally we should create a dependency injector for all dependencies and
1311// remove this.
1312- (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger {
1313 // Discard the previous messenger and keep the new one.
1314 if (binaryMessenger != _binaryMessenger) {
1316 _binaryMessenger = binaryMessenger;
1317 }
1318}
1319
1320#pragma mark - FlutterBinaryMessenger
1321
1322- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1323 [self sendOnChannel:channel message:message binaryReply:nil];
1324}
1325
1326- (void)sendOnChannel:(NSString*)channel
1327 message:(NSData*)message
1328 binaryReply:(FlutterBinaryReply)callback {
1329 NSParameterAssert(channel);
1330 NSAssert(_shell && _shell->IsSetup(),
1331 @"Sending a message before the FlutterEngine has been run.");
1333 (callback == nil) ? nullptr
1334 : fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
1335 ^(NSData* reply) {
1336 callback(reply);
1337 },
1338 _shell->GetTaskRunners().GetPlatformTaskRunner());
1339 std::unique_ptr<flutter::PlatformMessage> platformMessage =
1340 (message == nil) ? std::make_unique<flutter::PlatformMessage>(channel.UTF8String, response)
1341 : std::make_unique<flutter::PlatformMessage>(
1342 channel.UTF8String, flutter::CopyNSDataToMapping(message), response);
1343
1344 _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1345 // platformMessage takes ownership of response.
1346 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1347}
1348
1349- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
1351}
1352
1353- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
1354 binaryMessageHandler:
1356 return [self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1357}
1358
1360 setMessageHandlerOnChannel:(NSString*)channel
1361 binaryMessageHandler:(FlutterBinaryMessageHandler)handler
1362 taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
1363 NSParameterAssert(channel);
1364 if (_shell && _shell->IsSetup()) {
1365 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
1366 handler, taskQueue);
1367 return [self.connections acquireConnectionForChannel:channel];
1368 } else {
1369 NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
1370 // Setting a handler to nil for a channel that has not yet been set up is a no-op.
1371 return [FlutterConnectionCollection makeErrorConnectionWithErrorCode:-1L];
1372 }
1373}
1374
1375- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
1376 if (_shell && _shell->IsSetup()) {
1377 NSString* channel = [self.connections cleanupConnectionWithID:connection];
1378 if (channel.length > 0) {
1379 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String, nil,
1380 nil);
1381 }
1382 }
1383}
1384
1385#pragma mark - FlutterTextureRegistry
1386
1387- (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture {
1388 FML_DCHECK(self.platformView);
1389 int64_t textureId = self.nextTextureId++;
1390 self.platformView->RegisterExternalTexture(textureId, texture);
1391 return textureId;
1392}
1393
1394- (void)unregisterTexture:(int64_t)textureId {
1395 _shell->GetPlatformView()->UnregisterTexture(textureId);
1396}
1397
1398- (void)textureFrameAvailable:(int64_t)textureId {
1399 _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1400}
1401
1402- (NSString*)lookupKeyForAsset:(NSString*)asset {
1404}
1405
1406- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1407 return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
1408}
1409
1410- (id<FlutterPluginRegistry>)pluginRegistry {
1411 return self;
1412}
1413
1414#pragma mark - FlutterPluginRegistry
1415
1416- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
1417 NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
1418 self.pluginPublications[pluginKey] = [NSNull null];
1419 FlutterEnginePluginRegistrar* result = [[FlutterEnginePluginRegistrar alloc] initWithKey:pluginKey
1420 flutterEngine:self];
1421 self.registrars[pluginKey] = result;
1422 return result;
1423}
1424
1425- (NSObject<FlutterApplicationRegistrar>*)registrarForApplication:(NSString*)key {
1426 NSAssert(self.pluginPublications[key] == nil, @"Duplicate key: %@", key);
1427 self.pluginPublications[key] = [NSNull null];
1429 [[FlutterEngineApplicationRegistrar alloc] initWithKey:key flutterEngine:self];
1430 self.registrars[key] = result;
1431 return result;
1432}
1433
1434- (BOOL)hasPlugin:(NSString*)pluginKey {
1435 return _pluginPublications[pluginKey] != nil;
1436}
1437
1438- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1439 return _pluginPublications[pluginKey];
1440}
1441
1442- (void)addSceneLifeCycleDelegate:(NSObject<FlutterSceneLifeCycleDelegate>*)delegate {
1443 [self.sceneLifeCycleDelegate addDelegate:delegate];
1444}
1445
1446#pragma mark - Notifications
1447
1448- (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1449 [self flutterWillEnterForeground:notification];
1450}
1451
1452- (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1453 [self flutterDidEnterBackground:notification];
1454}
1455
1456- (void)applicationWillEnterForeground:(NSNotification*)notification {
1457 [self flutterWillEnterForeground:notification];
1458}
1459
1460- (void)applicationDidEnterBackground:(NSNotification*)notification {
1461 [self flutterDidEnterBackground:notification];
1462}
1463
1464- (void)flutterWillEnterForeground:(NSNotification*)notification {
1465 [self setIsGpuDisabled:NO];
1466}
1467
1468- (void)flutterDidEnterBackground:(NSNotification*)notification {
1469 [self setIsGpuDisabled:YES];
1470 [self notifyLowMemory];
1471}
1472
1473- (void)onMemoryWarning:(NSNotification*)notification {
1474 [self notifyLowMemory];
1475}
1476
1477- (void)setIsGpuDisabled:(BOOL)value {
1478 if (_shell) {
1479 _shell->SetGpuAvailability(value ? flutter::GpuAvailability::kUnavailable
1481 }
1482 _isGpuDisabled = value;
1483}
1484
1485#pragma mark - Locale updates
1486
1487- (void)onLocaleUpdated:(NSNotification*)notification {
1488 // Get and pass the user's preferred locale list to dart:ui.
1489 NSMutableArray<NSString*>* localeData = [[NSMutableArray alloc] init];
1490 NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1491 for (NSString* localeID in preferredLocales) {
1492 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1493 NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1494 NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1495 NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1496 NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1497 if (!languageCode) {
1498 continue;
1499 }
1500 [localeData addObject:languageCode];
1501 [localeData addObject:(countryCode ? countryCode : @"")];
1502 [localeData addObject:(scriptCode ? scriptCode : @"")];
1503 [localeData addObject:(variantCode ? variantCode : @"")];
1504 }
1505 if (localeData.count == 0) {
1506 return;
1507 }
1508 [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1509}
1510
1511- (void)onStatusBarTap {
1512 // Called by FlutterViewController to notify the framework that a tap landed
1513 // on the status bar, and the most relevant vertical scroll view visible in the
1514 // app, if applicable, should scroll to top.
1515 [self.statusBarChannel invokeMethod:@"handleScrollToTop" arguments:nil];
1516}
1517
1518- (void)waitForFirstFrameSync:(NSTimeInterval)timeout
1519 callback:(NS_NOESCAPE void (^_Nonnull)(BOOL didTimeout))callback {
1520 fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1521 fml::Status status = self.shell.WaitForFirstFrame(waitTime);
1523}
1524
1525- (void)waitForFirstFrame:(NSTimeInterval)timeout
1526 callback:(void (^_Nonnull)(BOOL didTimeout))callback {
1527 dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1528 dispatch_group_t group = dispatch_group_create();
1529
1530 __weak FlutterEngine* weakSelf = self;
1531 __block BOOL didTimeout = NO;
1532 dispatch_group_async(group, queue, ^{
1533 FlutterEngine* strongSelf = weakSelf;
1534 if (!strongSelf) {
1535 return;
1536 }
1537
1538 fml::TimeDelta waitTime = fml::TimeDelta::FromMilliseconds(timeout * 1000);
1539 fml::Status status = strongSelf.shell.WaitForFirstFrame(waitTime);
1540 didTimeout = status.code() == fml::StatusCode::kDeadlineExceeded;
1541 });
1542
1543 // Only execute the main queue task once the background task has completely finished executing.
1544 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
1545 // Strongly capture self on the task dispatched to the main thread.
1546 //
1547 // When we capture weakSelf strongly in the above block on a background thread, we risk the
1548 // possibility that all other strong references to FlutterEngine go out of scope while the block
1549 // executes and that the engine is dealloc'ed at the end of the above block on a background
1550 // thread. FlutterEngine is not safe to release on any thread other than the main thread.
1551 //
1552 // self is never nil here since it's a strong reference that's verified non-nil above, but we
1553 // use a conditional check to avoid an unused expression compiler warning.
1554 FlutterEngine* strongSelf = self;
1555 if (!strongSelf) {
1556 return;
1557 }
1558 callback(didTimeout);
1559 });
1560}
1561
1562- (FlutterEngine*)spawnWithEntrypoint:(/*nullable*/ NSString*)entrypoint
1563 libraryURI:(/*nullable*/ NSString*)libraryURI
1564 initialRoute:(/*nullable*/ NSString*)initialRoute
1565 entrypointArgs:(/*nullable*/ NSArray<NSString*>*)entrypointArgs {
1566 NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
1567 FlutterEngine* result = [[FlutterEngine alloc] initWithName:self.labelPrefix
1568 project:self.dartProject
1569 allowHeadlessExecution:self.allowHeadlessExecution];
1570 flutter::RunConfiguration configuration =
1571 [self.dartProject runConfigurationForEntrypoint:entrypoint
1572 libraryOrNil:libraryURI
1573 entrypointArgs:entrypointArgs];
1574
1575 configuration.SetEngineId(result.engineIdentifier);
1576
1579 // Static-cast safe since this class always creates PlatformViewIOS instances.
1580 flutter::PlatformViewIOS* ios_platform_view =
1581 static_cast<flutter::PlatformViewIOS*>(platform_view.get());
1582 std::shared_ptr<flutter::IOSContext> context = ios_platform_view->GetIosContext();
1583 FML_DCHECK(context);
1584
1585 // Lambda captures by pointers to ObjC objects are fine here because the
1586 // create call is synchronous.
1588 [result, context](flutter::Shell& shell) {
1589 [result recreatePlatformViewsController];
1590 result.platformViewsController.taskRunner = [[FlutterFMLTaskRunner alloc]
1591 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
1592 return std::make_unique<flutter::PlatformViewIOS>(
1593 shell, context, result.platformViewsController, shell.GetTaskRunners());
1594 };
1595
1597 [](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
1598
1599 std::string cppInitialRoute;
1600 if (initialRoute) {
1601 cppInitialRoute = [initialRoute UTF8String];
1602 }
1603
1604 std::unique_ptr<flutter::Shell> shell = _shell->Spawn(
1605 std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1606
1607 result->_threadHost = _threadHost;
1608 result->_profiler = _profiler;
1609 result->_isGpuDisabled = _isGpuDisabled;
1610 [result setUpShell:std::move(shell) withVMServicePublication:NO];
1611 return result;
1612}
1613
1614- (const flutter::ThreadHost&)threadHost {
1615 return *_threadHost;
1616}
1617
1618- (FlutterDartProject*)project {
1619 return self.dartProject;
1620}
1621
1622- (void)sendDeepLinkToFramework:(NSURL*)url completionHandler:(void (^)(BOOL success))completion {
1623 __weak FlutterEngine* weakSelf = self;
1624 [self waitForFirstFrame:3.0
1625 callback:^(BOOL didTimeout) {
1626 if (didTimeout) {
1627 [FlutterLogger
1628 logError:@"Timeout waiting for first frame when launching a URL."];
1629 completion(NO);
1630 } else {
1631 // invove the method and get the result
1632 [weakSelf.navigationChannel
1633 invokeMethod:@"pushRouteInformation"
1634 arguments:@{
1635 @"location" : url.absoluteString ?: [NSNull null],
1636 }
1637 result:^(id _Nullable result) {
1638 BOOL success =
1639 [result isKindOfClass:[NSNumber class]] && [result boolValue];
1640 if (!success) {
1641 // Logging the error if the result is not successful
1642 [FlutterLogger
1643 logError:@"Failed to handle route information in Flutter."];
1644 }
1645 completion(success);
1646 }];
1647 }
1648 }];
1649}
1650
1651@end
1652
1653@implementation FlutterEngineBaseRegistrar
1654
1655- (instancetype)initWithKey:(NSString*)key flutterEngine:(FlutterEngine*)flutterEngine {
1656 self = [super init];
1657 NSAssert(self, @"Super init cannot be nil");
1658 _key = [key copy];
1660 return self;
1661}
1662
1663- (NSObject<FlutterBinaryMessenger>*)messenger {
1665}
1666- (NSObject<FlutterTextureRegistry>*)textures {
1668}
1669
1670- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1671 withId:(NSString*)factoryId {
1672 [self registerViewFactory:factory
1673 withId:factoryId
1674 gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
1675}
1676
1677- (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
1678 withId:(NSString*)factoryId
1679 gestureRecognizersBlockingPolicy:
1680 (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy {
1681 [_flutterEngine.platformViewsController registerViewFactory:factory
1682 withId:factoryId
1683 gestureRecognizersBlockingPolicy:gestureRecognizersBlockingPolicy];
1684}
1685
1686@end
1687
1688@implementation FlutterEnginePluginRegistrar
1689
1690- (nullable UIViewController*)viewController {
1691 return self.flutterEngine.viewController;
1692}
1693
1694- (void)publish:(NSObject*)value {
1695 self.flutterEngine.pluginPublications[self.key] = value;
1696}
1697
1698- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
1699 channel:(FlutterMethodChannel*)channel {
1700 [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1701 [delegate handleMethodCall:call result:result];
1702 }];
1703}
1704
1705/// Returns YES if the Flutter plugin responds to any legacy app lifecycle selectors.
1706/// These selectors correspond to UIApplicationDelegate methods that have scene-based
1707/// equivalents and require migration to FlutterSceneLifeCycleDelegate.
1708static BOOL FLTFlutterPluginRespondsToLegacyAppLifecycleSelectors(
1709 NSObject<FlutterPlugin>* delegate) {
1710 SEL selectors[] = {
1711 @selector(applicationDidBecomeActive:),
1712 @selector(applicationWillResignActive:),
1713 @selector(applicationWillEnterForeground:),
1714 @selector(applicationDidEnterBackground:),
1715 @selector(application:continueUserActivity:restorationHandler:),
1716 @selector(application:performActionForShortcutItem:completionHandler:),
1717 @selector(application:openURL:options:),
1718 @selector(application:performFetchWithCompletionHandler:),
1719 };
1720 for (SEL sel : selectors) {
1721 if ([delegate respondsToSelector:sel]) {
1722 return YES;
1723 }
1724 }
1725 return NO;
1726}
1727
1728- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {
1729 id<UIApplicationDelegate> appDelegate = FlutterSharedApplication.application.delegate;
1730 if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) {
1731 id<FlutterAppLifeCycleProvider> lifeCycleProvider =
1732 (id<FlutterAppLifeCycleProvider>)appDelegate;
1733 [lifeCycleProvider addApplicationLifeCycleDelegate:delegate];
1734 }
1735 if (![delegate conformsToProtocol:@protocol(FlutterSceneLifeCycleDelegate)] &&
1736 FLTFlutterPluginRespondsToLegacyAppLifecycleSelectors(delegate)) {
1737 [FlutterLogger
1738 logWarning:
1739 [NSString stringWithFormat:
1740 @"Plugin %@ uses deprecated application lifecycle events. Please contact "
1741 @"plugin maintainers and request UIScene lifecycle support. This will be "
1742 @"required in a future version of Flutter. See "
1743 @"https://docs.flutter.dev/release/breaking-changes/"
1744 @"uiscenedelegate#migration-guide-for-flutter-plugins",
1745 self.key]];
1746 }
1747}
1748
1749- (void)addSceneDelegate:(NSObject<FlutterSceneLifeCycleDelegate>*)delegate {
1750 // If the plugin conforms to FlutterSceneLifeCycleDelegate, add it to the engine.
1751 [self.flutterEngine addSceneLifeCycleDelegate:delegate];
1752}
1753
1754- (NSString*)lookupKeyForAsset:(NSString*)asset {
1755 return [self.flutterEngine lookupKeyForAsset:asset];
1756}
1757
1758- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1759 return [self.flutterEngine lookupKeyForAsset:asset fromPackage:package];
1760}
1761
1762- (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1763 return [self.flutterEngine valuePublishedByPlugin:pluginKey];
1764}
1765
1766@end
1767
1769@end
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
FlutterPlatformViewGestureRecognizersBlockingPolicy
BOOL _restorationEnabled
static NSObject< FlutterTaskQueue > * MakeBackgroundTaskQueue()
void SetNextFrameCallback(const fml::closure &closure)
Sets a callback that gets executed when the rasterizer renders the next frame. Due to the asynchronou...
const std::shared_ptr< IOSContext > & GetIosContext()
Specifies all the configuration required by the runtime library to launch the root isolate....
void SetEngineId(std::optional< int64_t > engine_id)
Sets the engine identifier to be passed to the platform dispatcher.
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, const TaskRunners &task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
Definition shell.cc:222
fml::Status WaitForFirstFrame(fml::TimeDelta timeout)
Pauses the calling thread until the first frame is presented.
Definition shell.cc:2357
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition shell.h:121
static void EnsureInitializedForCurrentThread()
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
fml::StatusCode code() const
Definition status.h:63
@ kNormal
Default priority level.
@ kRaster
Suitable for thread which raster data.
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
@ kDisplay
Suitable for threads which generate data for the display.
static void SetCurrentThreadName(const ThreadConfig &config)
Definition thread.cc:135
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
uint32_t location
int32_t value
FlutterEngineResult FlutterEngineGetProcAddresses(FlutterEngineProcTable *table)
Gets the table of engine function pointers.
Definition embedder.cc:3737
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1465
@ kFlutterKeyEventTypeDown
Definition embedder.h:1386
@ kFlutterKeyEventTypeUp
Definition embedder.h:1385
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1387
FlutterEngine engine
Definition main.cc:84
VkQueue queue
Definition main.cc:71
const char * message
return TRUE
const gchar * channel
const gchar FlBinaryMessengerMessageHandler handler
HWND(* FlutterPlatformViewFactory)(const FlutterPlatformViewCreationParameters *)
FlutterDesktopBinaryReply callback
#define FML_DCHECK(condition)
Definition logging.h:122
NSObject< FlutterBinaryMessenger > * parent
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
NSString * lookupKeyForAsset:(NSString *asset)
const flutter::Settings & settings()
FlutterEngine * flutterEngine
nullable FlutterFMLTaskRunner * platformTaskRunner()
NSObject< FlutterBinaryMessenger > * binaryMessenger
flutter::PlatformViewIOS * platformView()
flutter::Shell & shell()
FlutterMethodChannel * localizationChannel
NSObject< FlutterTextureRegistry > * textureRegistry
nullable FlutterFMLTaskRunner * rasterTaskRunner()
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
NSObject< FlutterTextureRegistry > * parent
FlutterFMLTaskRunner * _uiTaskRunnerWrapper
NSString *const FlutterDefaultDartEntrypoint
std::shared_ptr< flutter::SamplingProfiler > _profiler
std::unique_ptr< flutter::Shell > _shell
NSObject< FlutterApplicationRegistrar > * _appRegistrar
NSString *const kFlutterKeyDataChannel
NSString *const FlutterDefaultInitialRoute
FlutterFMLTaskRunner * _rasterTaskRunnerWrapper
flutter::IOSRenderingAPI _renderingApi
FlutterTextureRegistryRelay * _textureRegistry
static FLUTTER_ASSERT_ARC void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig &config)
static constexpr int kNumProfilerSamplesPerSec
FlutterFMLTaskRunner * _platformTaskRunnerWrapper
NSString *const kFlutterApplicationRegistrarKey
FlutterBinaryMessengerRelay * _binaryMessenger
FlutterViewController * viewController
FlutterTextInputPlugin * textInputPlugin
size_t length
BOOL _allowHeadlessExecution
__weak FlutterEngine * _flutterEngine
FlTexture * texture
constexpr int64_t kFlutterImplicitViewId
Definition constants.h:35
fml::MallocMapping CopyNSDataToMapping(NSData *data)
bool EnableTracingIfNecessary(const Settings &vm_settings)
Enables tracing in the process so that JIT mode VMs may be launched. Explicitly enabling tracing is n...
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
GpuAvailability
Values for |Shell::SetGpuAvailability|.
Definition shell.h:64
@ kAvailable
Indicates that GPU operations should be permitted.
RefPtr< T > MakeRefCounted(Args &&... args)
Definition ref_ptr.h:253
Definition ref_ptr.h:261
std::vector< FlutterEngineDisplay > * displays
NSObject< FlutterTextureRegistry > * textures()
NSObject< FlutterBinaryMessenger > * messenger()
instancetype sharedInstance()
impeller::ShaderType type
Function-pointer-based versions of the APIs above.
Definition embedder.h:3746
FlutterKeyEventType type
The event kind.
Definition embedder.h:1428
const char * character
Definition embedder.h:1447
uint64_t synthesized
Definition key_data.h:70
uint64_t logical
Definition key_data.h:66
uint64_t physical
Definition key_data.h:65
KeyEventType type
Definition key_data.h:64
uint64_t timestamp
Definition key_data.h:63
std::string advisory_script_entrypoint
Definition settings.h:176
bool enable_embedder_api
Definition settings.h:363
std::string advisory_script_uri
Definition settings.h:173
MergedPlatformUIThread merged_platform_ui_thread
Definition settings.h:382
std::string route
Definition settings.h:125
static std::string MakeThreadName(Type type, const std::string &prefix)
Use the prefix and thread type to generator a thread name.
The collection of all the threads used by the engine.
Definition thread_host.h:21
The ThreadConfig is the thread info include thread name, thread priority.
Definition thread.h:35
ThreadPriority priority
Definition thread.h:45
const uintptr_t id
int BOOL