210- (int64_t)engineIdentifier {
211 return reinterpret_cast<int64_t
>((__bridge
void*)
self);
214- (instancetype)init {
215 return [
self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
218- (instancetype)initWithName:(NSString*)labelPrefix {
219 return [
self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
222- (instancetype)initWithName:(NSString*)labelPrefix project:(
FlutterDartProject*)project {
223 return [
self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
226- (instancetype)initWithName:(NSString*)labelPrefix
228 allowHeadlessExecution:(
BOOL)allowHeadlessExecution {
229 return [
self initWithName:labelPrefix
231 allowHeadlessExecution:allowHeadlessExecution
232 restorationEnabled:NO];
235- (instancetype)initWithName:(NSString*)labelPrefix
237 allowHeadlessExecution:(
BOOL)allowHeadlessExecution
238 restorationEnabled:(
BOOL)restorationEnabled {
240 NSAssert(
self,
@"Super init cannot be nil");
241 NSAssert(labelPrefix,
@"labelPrefix is required");
245 _labelPrefix = [labelPrefix copy];
249 if (_enableEmbedderAPI) {
250 NSLog(
@"============== iOS: enable_embedder_api is on ==============");
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.");
264 _pluginPublications = [[NSMutableDictionary alloc] init];
265 _registrars = [[NSMutableDictionary alloc] init];
266 [
self recreatePlatformViewsController];
269 _connections = [[FlutterConnectionCollection alloc] init];
271 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
272 [center addObserver:self
273 selector:@selector(onMemoryWarning:)
274 name:UIApplicationDidReceiveMemoryWarningNotification
277 [
self setUpLifecycleNotifications:center];
279 [center addObserver:self
280 selector:@selector(onLocaleUpdated:)
281 name:NSCurrentLocaleDidChangeNotification
290 NSAssert([[NSThread currentThread] isMainThread],
@"Must be called on the main thread.");
291 return (__bridge
FlutterEngine*)
reinterpret_cast<void*
>(identifier);
294- (void)setUpLifecycleNotifications:(NSNotificationCenter*)center {
296 [center addObserver:self
297 selector:@selector(sceneWillConnect:)
298 name:UISceneWillConnectNotification
301 [center addObserver:self
302 selector:@selector(sceneWillEnterForeground:)
303 name:UISceneWillEnterForegroundNotification
305 [center addObserver:self
306 selector:@selector(sceneDidEnterBackground:)
307 name:UISceneDidEnterBackgroundNotification
311 [center addObserver:self
312 selector:@selector(applicationWillEnterForeground:)
313 name:UIApplicationWillEnterForegroundNotification
315 [center addObserver:self
316 selector:@selector(applicationDidEnterBackground:)
317 name:UIApplicationDidEnterBackgroundNotification
321- (void)sceneWillConnect:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
322 if (
self.viewController && ![
self.viewController shouldHandleSceneNotification:notification]) {
325 UIScene* scene = notification.object;
335 if (sceneLifeCycleDelegate != nil) {
336 return [sceneLifeCycleDelegate engine:self receivedConnectNotificationFor:scene];
341- (void)recreatePlatformViewsController {
346- (
flutter::IOSRenderingAPI)platformViewsRenderingAPI {
353 [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
354 if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
356 if ([registrar conformsToProtocol:@protocol(FlutterPluginRegistrar)]) {
357 [object detachFromEngineForRegistrar:((id<FlutterPluginRegistrar>)registrar)];
365 [_registrars enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineBaseRegistrar* registrar,
367 registrar.flutterEngine = nil;
373 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
374 if (_flutterViewControllerWillDeallocObserver) {
375 [center removeObserver:_flutterViewControllerWillDeallocObserver];
377 [center removeObserver:self];
385- (void)updateViewportMetrics:(
flutter::ViewportMetrics)viewportMetrics {
386 if (!
self.platformView) {
392- (void)dispatchPointerDataPacket:(
std::unique_ptr<
flutter::PointerDataPacket>)packet {
393 if (!
self.platformView) {
396 self.platformView->DispatchPointerDataPacket(std::move(packet));
399- (
BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(
flutter::PointData)location
400 viewId:(uint64_t)viewId {
401 if (!
self.platformView) {
404 return self.platformView->HitTest(viewId,
location).has_platform_view;
407- (void)installFirstFrameCallback:(
void (^)(
void))block {
408 if (!
self.platformView) {
422 [strongSelf.platformTaskRunner postTask:^{
428- (void)enableSemantics:(
BOOL)enabled withFlags:(int64_t)flags {
429 if (!
self.platformView) {
432 self.platformView->SetSemanticsEnabled(enabled);
433 self.platformView->SetAccessibilityFeatures(flags);
436- (void)notifyViewCreated {
437 if (!
self.platformView) {
440 self.platformView->NotifyCreated();
443- (void)notifyViewDestroyed {
444 if (!
self.platformView) {
447 self.platformView->NotifyDestroyed();
450- (
flutter::PlatformViewIOS*)platformView {
471 userData:(
void*)userData API_AVAILABLE(ios(13.4)) {
472 if (@available(iOS 13.4, *)) {
476 if (!
self.platformView) {
484 switch (event.
type) {
496 key_data.
logical =
event.logical;
499 auto packet = std::make_unique<flutter::KeyDataPacket>(key_data,
character);
500 NSData*
message = [NSData dataWithBytes:packet->data().data() length:packet->data().size()];
502 auto response = ^(NSData* reply) {
506 BOOL handled = FALSE;
507 if (reply.length == 1 && *
reinterpret_cast<const uint8_t*
>(reply.bytes) == 1) {
513 [
self sendOnChannel:kFlutterKeyDataChannel message:message binaryReply:response];
516- (void)ensureSemanticsEnabled {
517 if (!
self.platformView) {
520 self.platformView->SetSemanticsEnabled(
true);
526 self.platformView->SetOwnerViewController(_viewController);
527 [
self maybeSetupPlatformViewChannels];
528 [
self updateDisplays];
533 self.flutterViewControllerWillDeallocObserver =
534 [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
535 object:viewController
536 queue:[NSOperationQueue mainQueue]
537 usingBlock:^(NSNotification* note) {
538 [weakSelf notifyViewControllerDeallocated];
541 self.flutterViewControllerWillDeallocObserver = nil;
542 [
self notifyLowMemory];
548 self.platformView->attachView();
551- (void)setFlutterViewControllerWillDeallocObserver:(
id<NSObject>)observer {
552 if (observer != _flutterViewControllerWillDeallocObserver) {
553 if (_flutterViewControllerWillDeallocObserver) {
554 [[NSNotificationCenter defaultCenter]
555 removeObserver:_flutterViewControllerWillDeallocObserver];
557 _flutterViewControllerWillDeallocObserver = observer;
561- (void)notifyViewControllerDeallocated {
562 [
self.lifecycleChannel sendMessage:@"AppLifecycleState.detached"];
563 self.textInputPlugin.viewController = nil;
564 if (!
self.allowHeadlessExecution) {
565 [
self destroyContext];
566 }
else if (
self.platformView) {
567 self.platformView->SetOwnerViewController({});
569 [
self.textInputPlugin resetViewResponder];
570 _viewController = nil;
573- (void)destroyContext {
574 [
self resetChannels];
575 self.isolateId = nil;
579 _platformViewsController = nil;
869static void SetEntryPoint(
flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
871 FML_DCHECK(entrypoint) <<
"Must specify entrypoint if specifying library";
874 }
else if (entrypoint) {
883- (
BOOL)createShell:(NSString*)entrypoint
884 libraryURI:(NSString*)libraryURI
885 initialRoute:(NSString*)initialRoute {
887 [FlutterLogger logWarning:@"This FlutterEngine was already invoked."];
891 self.initialRoute = initialRoute;
893 auto settings = [
self.dartProject settings];
894 if (initialRoute != nil) {
895 self.initialRoute = initialRoute;
896 }
else if (settings.
route.empty() ==
false) {
897 self.initialRoute = [NSString stringWithUTF8String:settings.route.c_str()];
900 auto platformData = [
self.dartProject defaultPlatformData];
902 SetEntryPoint(&settings, entrypoint, libraryURI);
904 NSString* threadLabel = [
FlutterEngine generateThreadLabel:self.labelPrefix];
905 _threadHost = std::make_shared<flutter::ThreadHost>();
906 *_threadHost = MakeThreadHost(threadLabel, settings);
913 return std::unique_ptr<flutter::PlatformViewIOS>();
915 [strongSelf recreatePlatformViewsController];
917 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
918 return std::make_unique<flutter::PlatformViewIOS>(
919 shell, strongSelf->_renderingApi, strongSelf.platformViewsController,
920 shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(),
921 shell.GetIsGpuDisabledSyncSwitch());
925 [](
flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
932 ui_runner = _threadHost->ui_thread->GetTaskRunner();
936 _threadHost->raster_thread->GetTaskRunner(),
938 _threadHost->io_thread->GetTaskRunner()
942 self.isGpuDisabled =
self.viewController
943 ?
self.viewController.stateIsBackground
946 UIApplicationStateBackground;
953 on_create_platform_view,
954 on_create_rasterizer,
957 if (shell ==
nullptr) {
958 NSString* errorMessage = [NSString
959 stringWithFormat:@"Could not start a shell FlutterEngine with entrypoint: %@", entrypoint];
960 [FlutterLogger logError:errorMessage];
962 [
self setUpShell:std::move(shell)
963 withVMServicePublication:settings.enable_vm_service_publication];
965 [
self startProfiler];
972- (
BOOL)performImplicitEngineCallback {
974 if ([appDelegate conformsToProtocol:@protocol(FlutterImplicitEngineDelegate)]) {
975 id<FlutterImplicitEngineDelegate> provider = (id<FlutterImplicitEngineDelegate>)appDelegate;
977 initWithEngine:self]];
983- (void)updateDisplays {
988 auto vsync_waiter =
_shell->GetVsyncWaiter().lock();
989 auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
990 std::vector<std::unique_ptr<flutter::Display>>
displays;
991 auto screen_size = UIScreen.mainScreen.nativeBounds.size;
992 auto scale = UIScreen.mainScreen.scale;
993 displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
994 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
999 return [
self runWithEntrypoint:FlutterDefaultDartEntrypoint
1001 initialRoute:FlutterDefaultInitialRoute];
1004- (
BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
1005 return [
self runWithEntrypoint:entrypoint
1006 libraryURI:libraryURI
1007 initialRoute:FlutterDefaultInitialRoute];
1010- (
BOOL)runWithEntrypoint:(NSString*)entrypoint {
1011 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
1014- (
BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
1015 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
1018- (
BOOL)runWithEntrypoint:(NSString*)entrypoint
1019 libraryURI:(NSString*)libraryURI
1020 initialRoute:(NSString*)initialRoute {
1021 return [
self runWithEntrypoint:entrypoint
1022 libraryURI:libraryURI
1023 initialRoute:initialRoute
1024 entrypointArgs:nil];
1027- (
BOOL)runWithEntrypoint:(NSString*)entrypoint
1028 libraryURI:(NSString*)libraryURI
1029 initialRoute:(NSString*)initialRoute
1030 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
1031 if ([
self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
1032 [
self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
1035 return _shell !=
nullptr;
1038- (void)notifyLowMemory {
1040 _shell->NotifyLowMemoryWarning();
1042 [
self.systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
1045#pragma mark - Text input delegate
1048 updateEditingClient:(
int)client
1049 withState:(NSDictionary*)state {
1050 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingState"
1051 arguments:@[ @(client), state ]];
1055 updateEditingClient:(
int)client
1056 withState:(NSDictionary*)state
1057 withTag:(NSString*)tag {
1058 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithTag"
1059 arguments:@[ @(client), @{tag : state} ]];
1063 updateEditingClient:(
int)client
1064 withDelta:(NSDictionary*)delta {
1065 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1066 arguments:@[ @(client), delta ]];
1070 updateFloatingCursor:(FlutterFloatingCursorDragState)state
1071 withClient:(
int)client
1072 withPosition:(NSDictionary*)position {
1073 NSString* stateString;
1075 case FlutterFloatingCursorDragStateStart:
1076 stateString =
@"FloatingCursorDragState.start";
1078 case FlutterFloatingCursorDragStateUpdate:
1079 stateString =
@"FloatingCursorDragState.update";
1081 case FlutterFloatingCursorDragStateEnd:
1082 stateString =
@"FloatingCursorDragState.end";
1085 [
self.textInputChannel invokeMethod:@"TextInputClient.updateFloatingCursor"
1086 arguments:@[ @(client), stateString, position ]];
1090 performAction:(FlutterTextInputAction)action
1091 withClient:(
int)client {
1092 NSString* actionString;
1094 case FlutterTextInputActionUnspecified:
1099 actionString =
@"TextInputAction.unspecified";
1101 case FlutterTextInputActionDone:
1102 actionString =
@"TextInputAction.done";
1104 case FlutterTextInputActionGo:
1105 actionString =
@"TextInputAction.go";
1107 case FlutterTextInputActionSend:
1108 actionString =
@"TextInputAction.send";
1110 case FlutterTextInputActionSearch:
1111 actionString =
@"TextInputAction.search";
1113 case FlutterTextInputActionNext:
1114 actionString =
@"TextInputAction.next";
1116 case FlutterTextInputActionContinue:
1117 actionString =
@"TextInputAction.continueAction";
1119 case FlutterTextInputActionJoin:
1120 actionString =
@"TextInputAction.join";
1122 case FlutterTextInputActionRoute:
1123 actionString =
@"TextInputAction.route";
1125 case FlutterTextInputActionEmergencyCall:
1126 actionString =
@"TextInputAction.emergencyCall";
1128 case FlutterTextInputActionNewline:
1129 actionString =
@"TextInputAction.newline";
1132 [
self.textInputChannel invokeMethod:@"TextInputClient.performAction"
1133 arguments:@[ @(client), actionString ]];
1137 showAutocorrectionPromptRectForStart:(NSUInteger)start
1139 withClient:(
int)client {
1140 [
self.textInputChannel invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1141 arguments:@[ @(client), @(start), @(end) ]];
1145 willDismissEditMenuWithTextInputClient:(
int)client {
1146 [
self.platformChannel invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1147 arguments:@[ @(client) ]];
1151 shareSelectedText:(NSString*)selectedText {
1152 [
self.platformPlugin showShareViewController:selectedText];
1156 searchWebWithSelectedText:(NSString*)selectedText {
1157 [
self.platformPlugin searchWeb:selectedText];
1161 lookUpSelectedText:(NSString*)selectedText {
1162 [
self.platformPlugin showLookUpViewController:selectedText];
1166 performContextMenuCustomActionWithActionID:(NSString*)actionID
1167 textInputClient:(
int)client {
1168 [
self.platformChannel invokeMethod:@"ContextMenu.onPerformCustomAction"
1169 arguments:@[ @(client), actionID ]];
1172#pragma mark - FlutterViewEngineDelegate
1178 [
self.textInputChannel invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1182 focusElement:(UIScribbleElementIdentifier)elementIdentifier
1183 atPoint:(CGPoint)referencePoint
1188 [
self.textInputChannel
1189 invokeMethod:@"TextInputClient.focusElement"
1190 arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1195 requestElementsInRect:(CGRect)rect
1200 [
self.textInputChannel
1201 invokeMethod:@"TextInputClient.requestElementsInRect"
1202 arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1210 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1217 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionFinished" arguments:nil];
1221 insertTextPlaceholderWithSize:(CGSize)size
1222 withClient:(
int)client {
1226 [
self.textInputChannel invokeMethod:@"TextInputClient.insertTextPlaceholder"
1227 arguments:@[ @(client), @(size.width), @(size.height) ]];
1231 removeTextPlaceholder:(
int)client {
1235 [
self.textInputChannel invokeMethod:@"TextInputClient.removeTextPlaceholder"
1236 arguments:@[ @(client) ]];
1240 didResignFirstResponderWithTextInputClient:(
int)client {
1244 [
self.textInputChannel invokeMethod:@"TextInputClient.onConnectionClosed"
1245 arguments:@[ @(client) ]];
1266 dispatch_async(dispatch_get_main_queue(), ^(
void) {
1267 long platform_view_id = [
self.platformViewsController firstResponderPlatformViewId];
1268 if (platform_view_id == -1) {
1272 [
self.platformViewsChannel invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1276#pragma mark - Undo Manager Delegate
1278- (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1279 NSString*
action = (direction == FlutterUndoRedoDirectionUndo) ?
@"undo" :
@"redo";
1280 [
self.undoManagerChannel invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1283- (UIView<UITextInput>*)activeTextInputView {
1284 return [[
self textInputPlugin] textInputView];
1287- (NSUndoManager*)undoManager {
1288 return self.viewController.undoManager;
1291#pragma mark - Screenshot Delegate
1293- (
flutter::Rasterizer::Screenshot)takeScreenshot:(
flutter::Rasterizer::ScreenshotType)type
1294 asBase64Encoded:(
BOOL)base64Encode {
1296 return _shell->Screenshot(
type, base64Encode);
1299- (void)flutterViewAccessibilityDidCall {
1300 if (
self.viewController.view.accessibilityElements == nil) {
1301 [
self ensureSemanticsEnabled];
1305- (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
1309- (NSObject<FlutterTextureRegistry>*)textureRegistry {
1323#pragma mark - FlutterBinaryMessenger
1325- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1326 [
self sendOnChannel:channel message:message binaryReply:nil];
1329- (void)sendOnChannel:(NSString*)channel
1330 message:(NSData*)message
1334 @"Sending a message before the FlutterEngine has been run.");
1341 _shell->GetTaskRunners().GetPlatformTaskRunner());
1342 std::unique_ptr<flutter::PlatformMessage> platformMessage =
1343 (
message == nil) ? std::make_unique<flutter::PlatformMessage>(
channel.UTF8String, response)
1344 : std::make_unique<flutter::PlatformMessage>(
1347 _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1352- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
1357 binaryMessageHandler:
1359 return [
self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1363 setMessageHandlerOnChannel:(NSString*)channel
1365 taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
1368 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(
channel.UTF8String,
1370 return [
self.connections acquireConnectionForChannel:channel];
1372 NSAssert(!
handler,
@"Setting a message handler before the FlutterEngine has been run.");
1374 return [FlutterConnectionCollection makeErrorConnectionWithErrorCode:-1L];
1380 NSString*
channel = [
self.connections cleanupConnectionWithID:connection];
1382 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(
channel.UTF8String, nil,
1388#pragma mark - FlutterTextureRegistry
1392 int64_t textureId =
self.nextTextureId++;
1393 self.platformView->RegisterExternalTexture(textureId,
texture);
1397- (void)unregisterTexture:(int64_t)textureId {
1398 _shell->GetPlatformView()->UnregisterTexture(textureId);
1401- (void)textureFrameAvailable:(int64_t)textureId {
1402 _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1405- (NSString*)lookupKeyForAsset:(NSString*)asset {
1409- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1413- (
id<FlutterPluginRegistry>)pluginRegistry {
1417#pragma mark - FlutterPluginRegistry
1419- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
1420 NSAssert(
self.pluginPublications[pluginKey] == nil,
@"Duplicate plugin key: %@", pluginKey);
1421 self.pluginPublications[pluginKey] = [NSNull null];
1423 flutterEngine:self];
1424 self.registrars[pluginKey] = result;
1428- (NSObject<FlutterApplicationRegistrar>*)registrarForApplication:(NSString*)key {
1429 NSAssert(
self.pluginPublications[
key] == nil,
@"Duplicate key: %@",
key);
1430 self.pluginPublications[key] = [NSNull null];
1433 self.registrars[key] = result;
1437- (
BOOL)hasPlugin:(NSString*)pluginKey {
1438 return _pluginPublications[pluginKey] != nil;
1441- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1442 return _pluginPublications[pluginKey];
1445- (void)addSceneLifeCycleDelegate:(NSObject<FlutterSceneLifeCycleDelegate>*)delegate {
1446 [
self.sceneLifeCycleDelegate addDelegate:delegate];
1449#pragma mark - Notifications
1451- (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1452 if (
self.viewController && ![
self.viewController shouldHandleSceneNotification:notification]) {
1455 [
self flutterWillEnterForeground:notification];
1458- (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1459 if (
self.viewController && ![
self.viewController shouldHandleSceneNotification:notification]) {
1462 [
self flutterDidEnterBackground:notification];
1465- (void)applicationWillEnterForeground:(NSNotification*)notification {
1466 [
self flutterWillEnterForeground:notification];
1469- (void)applicationDidEnterBackground:(NSNotification*)notification {
1470 [
self flutterDidEnterBackground:notification];
1473- (void)flutterWillEnterForeground:(NSNotification*)notification {
1474 [
self setIsGpuDisabled:NO];
1477- (void)flutterDidEnterBackground:(NSNotification*)notification {
1478 [
self setIsGpuDisabled:YES];
1479 [
self notifyLowMemory];
1482- (void)onMemoryWarning:(NSNotification*)notification {
1483 [
self notifyLowMemory];
1486- (void)setIsGpuDisabled:(
BOOL)value {
1491 _isGpuDisabled =
value;
1494#pragma mark - Locale updates
1496- (void)onLocaleUpdated:(NSNotification*)notification {
1498 NSMutableArray<NSString*>* localeData = [[NSMutableArray alloc] init];
1499 NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1500 for (NSString* localeID in preferredLocales) {
1501 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1502 NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1503 NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1504 NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1505 NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1506 if (!languageCode) {
1509 [localeData addObject:languageCode];
1510 [localeData addObject:(countryCode ? countryCode : @"")];
1511 [localeData addObject:(scriptCode ? scriptCode : @"")];
1512 [localeData addObject:(variantCode ? variantCode : @"")];
1514 if (localeData.count == 0) {
1517 [
self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1520- (void)onStatusBarTap {
1524 [
self.statusBarChannel invokeMethod:@"handleScrollToTop" arguments:nil];
1527- (void)waitForFirstFrameSync:(NSTimeInterval)timeout
1528 callback:(NS_NOESCAPE
void (^_Nonnull)(
BOOL didTimeout))callback {
1534- (void)waitForFirstFrame:(NSTimeInterval)timeout
1535 callback:(
void (^_Nonnull)(
BOOL didTimeout))callback {
1536 dispatch_queue_t
queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1537 dispatch_group_t group = dispatch_group_create();
1540 __block
BOOL didTimeout = NO;
1541 dispatch_group_async(group,
queue, ^{
1553 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
1572 libraryURI:( NSString*)libraryURI
1573 initialRoute:( NSString*)initialRoute
1574 entrypointArgs:( NSArray<NSString*>*)entrypointArgs {
1575 NSAssert(
_shell,
@"Spawning from an engine without a shell (possibly not run).");
1577 project:self.dartProject
1578 allowHeadlessExecution:self.allowHeadlessExecution];
1580 [
self.dartProject runConfigurationForEntrypoint:entrypoint
1581 libraryOrNil:libraryURI
1582 entrypointArgs:entrypointArgs];
1584 configuration.
SetEngineId(result.engineIdentifier);
1598 [result recreatePlatformViewsController];
1600 initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner()];
1601 return std::make_unique<flutter::PlatformViewIOS>(
1602 shell,
context, result.platformViewsController, shell.GetTaskRunners());
1606 [](
flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
1608 std::string cppInitialRoute;
1610 cppInitialRoute = [initialRoute UTF8String];
1613 std::unique_ptr<flutter::Shell> shell =
_shell->Spawn(
1614 std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1616 result->_threadHost = _threadHost;
1618 result->_isGpuDisabled = _isGpuDisabled;
1619 [result setUpShell:std::move(shell) withVMServicePublication:NO];
1623- (const
flutter::ThreadHost&)threadHost {
1624 return *_threadHost;
1628 return self.dartProject;
1631- (void)sendDeepLinkToFramework:(NSURL*)url completionHandler:(
void (^)(
BOOL success))completion {
1633 [
self waitForFirstFrame:3.0
1634 callback:^(BOOL didTimeout) {
1637 logError:@"Timeout waiting for first frame when launching a URL."];
1641 [weakSelf.navigationChannel
1642 invokeMethod:@"pushRouteInformation"
1644 @"location" : url.absoluteString ?: [NSNull null],
1646 result:^(id _Nullable result) {
1648 [result isKindOfClass:[NSNumber class]] && [result boolValue];
1652 logError:@"Failed to handle route information in Flutter."];
1654 completion(success);
1664- (instancetype)initWithKey:(NSString*)key flutterEngine:(
FlutterEngine*)flutterEngine {
1665 self = [
super init];
1666 NSAssert(
self,
@"Super init cannot be nil");