203- (int64_t)engineIdentifier {
204 return reinterpret_cast<int64_t
>((__bridge
void*)
self);
207- (instancetype)init {
208 return [
self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
211- (instancetype)initWithName:(NSString*)labelPrefix {
212 return [
self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
215- (instancetype)initWithName:(NSString*)labelPrefix project:(
FlutterDartProject*)project {
216 return [
self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
219- (instancetype)initWithName:(NSString*)labelPrefix
221 allowHeadlessExecution:(
BOOL)allowHeadlessExecution {
222 return [
self initWithName:labelPrefix
224 allowHeadlessExecution:allowHeadlessExecution
225 restorationEnabled:NO];
228- (instancetype)initWithName:(NSString*)labelPrefix
230 allowHeadlessExecution:(
BOOL)allowHeadlessExecution
231 restorationEnabled:(
BOOL)restorationEnabled {
233 NSAssert(
self,
@"Super init cannot be nil");
234 NSAssert(labelPrefix,
@"labelPrefix is required");
238 _labelPrefix = [labelPrefix copy];
242 if (_enableEmbedderAPI) {
243 NSLog(
@"============== iOS: enable_embedder_api is on ==============");
250 @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
251 @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
252 @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
253 @"profile and release mode apps can be launched from the home screen.");
257 _pluginPublications = [[NSMutableDictionary alloc] init];
258 _registrars = [[NSMutableDictionary alloc] init];
259 [
self recreatePlatformViewsController];
262 _connections = [[FlutterConnectionCollection alloc] init];
264 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
265 [center addObserver:self
266 selector:@selector(onMemoryWarning:)
267 name:UIApplicationDidReceiveMemoryWarningNotification
270 [
self setUpLifecycleNotifications:center];
272 [center addObserver:self
273 selector:@selector(onLocaleUpdated:)
274 name:NSCurrentLocaleDidChangeNotification
283 NSAssert([[NSThread currentThread] isMainThread],
@"Must be called on the main thread.");
284 return (__bridge
FlutterEngine*)
reinterpret_cast<void*
>(identifier);
287- (void)setUpLifecycleNotifications:(NSNotificationCenter*)center {
289 [center addObserver:self
290 selector:@selector(sceneWillConnect:)
291 name:UISceneWillConnectNotification
294 [center addObserver:self
295 selector:@selector(sceneWillEnterForeground:)
296 name:UISceneWillEnterForegroundNotification
298 [center addObserver:self
299 selector:@selector(sceneDidEnterBackground:)
300 name:UISceneDidEnterBackgroundNotification
304 [center addObserver:self
305 selector:@selector(applicationWillEnterForeground:)
306 name:UIApplicationWillEnterForegroundNotification
308 [center addObserver:self
309 selector:@selector(applicationDidEnterBackground:)
310 name:UIApplicationDidEnterBackgroundNotification
314- (void)sceneWillConnect:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
315 UIScene* scene = notification.object;
325 if (sceneLifeCycleDelegate != nil) {
326 return [sceneLifeCycleDelegate engine:self receivedConnectNotificationFor:scene];
331- (void)recreatePlatformViewsController {
336- (
flutter::IOSRenderingAPI)platformViewsRenderingAPI {
343 [_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
344 if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
346 if ([registrar conformsToProtocol:@protocol(FlutterPluginRegistrar)]) {
347 [object detachFromEngineForRegistrar:((id<FlutterPluginRegistrar>)registrar)];
355 [_registrars enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineBaseRegistrar* registrar,
357 registrar.flutterEngine = nil;
363 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
364 if (_flutterViewControllerWillDeallocObserver) {
365 [center removeObserver:_flutterViewControllerWillDeallocObserver];
367 [center removeObserver:self];
375- (void)updateViewportMetrics:(
flutter::ViewportMetrics)viewportMetrics {
376 if (!
self.platformView) {
382- (void)dispatchPointerDataPacket:(
std::unique_ptr<
flutter::PointerDataPacket>)packet {
383 if (!
self.platformView) {
386 self.platformView->DispatchPointerDataPacket(std::move(packet));
389- (void)installFirstFrameCallback:(
void (^)(
void))block {
390 if (!
self.platformView) {
402 FML_DCHECK(strongSelf.rasterTaskRunner->RunsTasksOnCurrentThread());
404 strongSelf.platformTaskRunner->PostTask([block]() { block(); });
408- (void)enableSemantics:(
BOOL)enabled withFlags:(int64_t)flags {
409 if (!
self.platformView) {
412 self.platformView->SetSemanticsEnabled(enabled);
413 self.platformView->SetAccessibilityFeatures(flags);
416- (void)notifyViewCreated {
417 if (!
self.platformView) {
420 self.platformView->NotifyCreated();
423- (void)notifyViewDestroyed {
424 if (!
self.platformView) {
427 self.platformView->NotifyDestroyed();
430- (
flutter::PlatformViewIOS*)platformView {
437- (
fml::RefPtr<fml::TaskRunner>)platformTaskRunner {
441 return _shell->GetTaskRunners().GetPlatformTaskRunner();
444- (
fml::RefPtr<fml::TaskRunner>)uiTaskRunner {
448 return _shell->GetTaskRunners().GetUITaskRunner();
451- (
fml::RefPtr<fml::TaskRunner>)rasterTaskRunner {
455 return _shell->GetTaskRunners().GetRasterTaskRunner();
460 userData:(
void*)userData API_AVAILABLE(ios(13.4)) {
461 if (@available(iOS 13.4, *)) {
465 if (!
self.platformView) {
473 switch (event.
type) {
485 key_data.
logical =
event.logical;
488 auto packet = std::make_unique<flutter::KeyDataPacket>(key_data,
character);
489 NSData*
message = [NSData dataWithBytes:packet->data().data() length:packet->data().size()];
491 auto response = ^(NSData* reply) {
495 BOOL handled = FALSE;
496 if (reply.length == 1 && *
reinterpret_cast<const uint8_t*
>(reply.bytes) == 1) {
502 [
self sendOnChannel:kFlutterKeyDataChannel message:message binaryReply:response];
505- (void)ensureSemanticsEnabled {
506 if (!
self.platformView) {
509 self.platformView->SetSemanticsEnabled(
true);
515 self.platformView->SetOwnerViewController(_viewController);
516 [
self maybeSetupPlatformViewChannels];
517 [
self updateDisplays];
522 self.flutterViewControllerWillDeallocObserver =
523 [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
524 object:viewController
525 queue:[NSOperationQueue mainQueue]
526 usingBlock:^(NSNotification* note) {
527 [weakSelf notifyViewControllerDeallocated];
530 self.flutterViewControllerWillDeallocObserver = nil;
531 [
self notifyLowMemory];
537 self.platformView->attachView();
540- (void)setFlutterViewControllerWillDeallocObserver:(
id<NSObject>)observer {
541 if (observer != _flutterViewControllerWillDeallocObserver) {
542 if (_flutterViewControllerWillDeallocObserver) {
543 [[NSNotificationCenter defaultCenter]
544 removeObserver:_flutterViewControllerWillDeallocObserver];
546 _flutterViewControllerWillDeallocObserver = observer;
550- (void)notifyViewControllerDeallocated {
551 [
self.lifecycleChannel sendMessage:@"AppLifecycleState.detached"];
552 self.textInputPlugin.viewController = nil;
553 if (!
self.allowHeadlessExecution) {
554 [
self destroyContext];
555 }
else if (
self.platformView) {
556 self.platformView->SetOwnerViewController({});
558 [
self.textInputPlugin resetViewResponder];
559 _viewController = nil;
562- (void)destroyContext {
563 [
self resetChannels];
564 self.isolateId = nil;
568 _platformViewsController = nil;
841static void SetEntryPoint(
flutter::Settings* settings, NSString* entrypoint, NSString* libraryURI) {
843 FML_DCHECK(entrypoint) <<
"Must specify entrypoint if specifying library";
846 }
else if (entrypoint) {
855- (
BOOL)createShell:(NSString*)entrypoint
856 libraryURI:(NSString*)libraryURI
857 initialRoute:(NSString*)initialRoute {
859 [FlutterLogger logWarning:@"This FlutterEngine was already invoked."];
863 self.initialRoute = initialRoute;
865 auto settings = [
self.dartProject settings];
866 if (initialRoute != nil) {
867 self.initialRoute = initialRoute;
868 }
else if (settings.
route.empty() ==
false) {
869 self.initialRoute = [NSString stringWithUTF8String:settings.route.c_str()];
872 auto platformData = [
self.dartProject defaultPlatformData];
874 SetEntryPoint(&settings, entrypoint, libraryURI);
876 NSString* threadLabel = [
FlutterEngine generateThreadLabel:self.labelPrefix];
877 _threadHost = std::make_shared<flutter::ThreadHost>();
878 *_threadHost = MakeThreadHost(threadLabel, settings);
885 return std::unique_ptr<flutter::PlatformViewIOS>();
887 [strongSelf recreatePlatformViewsController];
888 strongSelf.platformViewsController.taskRunner =
889 shell.GetTaskRunners().GetPlatformTaskRunner();
890 return std::make_unique<flutter::PlatformViewIOS>(
891 shell, strongSelf->_renderingApi, strongSelf.platformViewsController,
892 shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(),
893 shell.GetIsGpuDisabledSyncSwitch());
897 [](
flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
904 ui_runner = _threadHost->ui_thread->GetTaskRunner();
908 _threadHost->raster_thread->GetTaskRunner(),
910 _threadHost->io_thread->GetTaskRunner()
914 self.isGpuDisabled =
self.viewController
915 ?
self.viewController.stateIsBackground
918 UIApplicationStateBackground;
925 on_create_platform_view,
926 on_create_rasterizer,
929 if (shell ==
nullptr) {
930 NSString* errorMessage = [NSString
931 stringWithFormat:@"Could not start a shell FlutterEngine with entrypoint: %@", entrypoint];
932 [FlutterLogger logError:errorMessage];
934 [
self setUpShell:std::move(shell)
935 withVMServicePublication:settings.enable_vm_service_publication];
937 [
self startProfiler];
944- (
BOOL)performImplicitEngineCallback {
946 if ([appDelegate conformsToProtocol:@protocol(FlutterImplicitEngineDelegate)]) {
947 id<FlutterImplicitEngineDelegate> provider = (id<FlutterImplicitEngineDelegate>)appDelegate;
949 initWithEngine:self]];
955- (void)updateDisplays {
960 auto vsync_waiter =
_shell->GetVsyncWaiter().lock();
961 auto vsync_waiter_ios = std::static_pointer_cast<flutter::VsyncWaiterIOS>(vsync_waiter);
962 std::vector<std::unique_ptr<flutter::Display>>
displays;
963 auto screen_size = UIScreen.mainScreen.nativeBounds.size;
964 auto scale = UIScreen.mainScreen.scale;
965 displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(
966 0, vsync_waiter_ios, screen_size.width, screen_size.height, scale));
971 return [
self runWithEntrypoint:FlutterDefaultDartEntrypoint
973 initialRoute:FlutterDefaultInitialRoute];
976- (
BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
977 return [
self runWithEntrypoint:entrypoint
978 libraryURI:libraryURI
979 initialRoute:FlutterDefaultInitialRoute];
982- (
BOOL)runWithEntrypoint:(NSString*)entrypoint {
983 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
986- (
BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
987 return [
self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
990- (
BOOL)runWithEntrypoint:(NSString*)entrypoint
991 libraryURI:(NSString*)libraryURI
992 initialRoute:(NSString*)initialRoute {
993 return [
self runWithEntrypoint:entrypoint
994 libraryURI:libraryURI
995 initialRoute:initialRoute
999- (
BOOL)runWithEntrypoint:(NSString*)entrypoint
1000 libraryURI:(NSString*)libraryURI
1001 initialRoute:(NSString*)initialRoute
1002 entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
1003 if ([
self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
1004 [
self launchEngine:entrypoint libraryURI:libraryURI entrypointArgs:entrypointArgs];
1007 return _shell !=
nullptr;
1010- (void)notifyLowMemory {
1012 _shell->NotifyLowMemoryWarning();
1014 [
self.systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
1017#pragma mark - Text input delegate
1020 updateEditingClient:(
int)client
1021 withState:(NSDictionary*)state {
1022 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingState"
1023 arguments:@[ @(client), state ]];
1027 updateEditingClient:(
int)client
1028 withState:(NSDictionary*)state
1029 withTag:(NSString*)tag {
1030 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithTag"
1031 arguments:@[ @(client), @{tag : state} ]];
1035 updateEditingClient:(
int)client
1036 withDelta:(NSDictionary*)delta {
1037 [
self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
1038 arguments:@[ @(client), delta ]];
1042 updateFloatingCursor:(FlutterFloatingCursorDragState)state
1043 withClient:(
int)client
1044 withPosition:(NSDictionary*)position {
1045 NSString* stateString;
1047 case FlutterFloatingCursorDragStateStart:
1048 stateString =
@"FloatingCursorDragState.start";
1050 case FlutterFloatingCursorDragStateUpdate:
1051 stateString =
@"FloatingCursorDragState.update";
1053 case FlutterFloatingCursorDragStateEnd:
1054 stateString =
@"FloatingCursorDragState.end";
1057 [
self.textInputChannel invokeMethod:@"TextInputClient.updateFloatingCursor"
1058 arguments:@[ @(client), stateString, position ]];
1062 performAction:(FlutterTextInputAction)action
1063 withClient:(
int)client {
1064 NSString* actionString;
1066 case FlutterTextInputActionUnspecified:
1071 actionString =
@"TextInputAction.unspecified";
1073 case FlutterTextInputActionDone:
1074 actionString =
@"TextInputAction.done";
1076 case FlutterTextInputActionGo:
1077 actionString =
@"TextInputAction.go";
1079 case FlutterTextInputActionSend:
1080 actionString =
@"TextInputAction.send";
1082 case FlutterTextInputActionSearch:
1083 actionString =
@"TextInputAction.search";
1085 case FlutterTextInputActionNext:
1086 actionString =
@"TextInputAction.next";
1088 case FlutterTextInputActionContinue:
1089 actionString =
@"TextInputAction.continueAction";
1091 case FlutterTextInputActionJoin:
1092 actionString =
@"TextInputAction.join";
1094 case FlutterTextInputActionRoute:
1095 actionString =
@"TextInputAction.route";
1097 case FlutterTextInputActionEmergencyCall:
1098 actionString =
@"TextInputAction.emergencyCall";
1100 case FlutterTextInputActionNewline:
1101 actionString =
@"TextInputAction.newline";
1104 [
self.textInputChannel invokeMethod:@"TextInputClient.performAction"
1105 arguments:@[ @(client), actionString ]];
1109 showAutocorrectionPromptRectForStart:(NSUInteger)start
1111 withClient:(
int)client {
1112 [
self.textInputChannel invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
1113 arguments:@[ @(client), @(start), @(end) ]];
1117 willDismissEditMenuWithTextInputClient:(
int)client {
1118 [
self.platformChannel invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
1119 arguments:@[ @(client) ]];
1123 shareSelectedText:(NSString*)selectedText {
1124 [
self.platformPlugin showShareViewController:selectedText];
1128 searchWebWithSelectedText:(NSString*)selectedText {
1129 [
self.platformPlugin searchWeb:selectedText];
1133 lookUpSelectedText:(NSString*)selectedText {
1134 [
self.platformPlugin showLookUpViewController:selectedText];
1138 performContextMenuCustomActionWithActionID:(NSString*)actionID
1139 textInputClient:(
int)client {
1140 [
self.platformChannel invokeMethod:@"ContextMenu.onPerformCustomAction"
1141 arguments:@[ @(client), actionID ]];
1144#pragma mark - FlutterViewEngineDelegate
1150 [
self.textInputChannel invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
1154 focusElement:(UIScribbleElementIdentifier)elementIdentifier
1155 atPoint:(CGPoint)referencePoint
1160 [
self.textInputChannel
1161 invokeMethod:@"TextInputClient.focusElement"
1162 arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
1167 requestElementsInRect:(CGRect)rect
1172 [
self.textInputChannel
1173 invokeMethod:@"TextInputClient.requestElementsInRect"
1174 arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
1182 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
1189 [
self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionFinished" arguments:nil];
1193 insertTextPlaceholderWithSize:(CGSize)size
1194 withClient:(
int)client {
1198 [
self.textInputChannel invokeMethod:@"TextInputClient.insertTextPlaceholder"
1199 arguments:@[ @(client), @(size.width), @(size.height) ]];
1203 removeTextPlaceholder:(
int)client {
1207 [
self.textInputChannel invokeMethod:@"TextInputClient.removeTextPlaceholder"
1208 arguments:@[ @(client) ]];
1212 didResignFirstResponderWithTextInputClient:(
int)client {
1216 [
self.textInputChannel invokeMethod:@"TextInputClient.onConnectionClosed"
1217 arguments:@[ @(client) ]];
1238 dispatch_async(dispatch_get_main_queue(), ^(
void) {
1239 long platform_view_id = [
self.platformViewsController firstResponderPlatformViewId];
1240 if (platform_view_id == -1) {
1244 [
self.platformViewsChannel invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
1248#pragma mark - Undo Manager Delegate
1250- (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
1251 NSString*
action = (direction == FlutterUndoRedoDirectionUndo) ?
@"undo" :
@"redo";
1252 [
self.undoManagerChannel invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
1255- (UIView<UITextInput>*)activeTextInputView {
1256 return [[
self textInputPlugin] textInputView];
1259- (NSUndoManager*)undoManager {
1260 return self.viewController.undoManager;
1263#pragma mark - Screenshot Delegate
1265- (
flutter::Rasterizer::Screenshot)takeScreenshot:(
flutter::Rasterizer::ScreenshotType)type
1266 asBase64Encoded:(
BOOL)base64Encode {
1268 return _shell->Screenshot(
type, base64Encode);
1271- (void)flutterViewAccessibilityDidCall {
1272 if (
self.viewController.view.accessibilityElements == nil) {
1273 [
self ensureSemanticsEnabled];
1277- (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
1281- (NSObject<FlutterTextureRegistry>*)textureRegistry {
1295#pragma mark - FlutterBinaryMessenger
1297- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
1298 [
self sendOnChannel:channel message:message binaryReply:nil];
1301- (void)sendOnChannel:(NSString*)channel
1302 message:(NSData*)message
1306 @"Sending a message before the FlutterEngine has been run.");
1313 _shell->GetTaskRunners().GetPlatformTaskRunner());
1314 std::unique_ptr<flutter::PlatformMessage> platformMessage =
1315 (
message == nil) ? std::make_unique<flutter::PlatformMessage>(
channel.UTF8String, response)
1316 : std::make_unique<flutter::PlatformMessage>(
1319 _shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
1324- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
1329 binaryMessageHandler:
1331 return [
self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
1335 setMessageHandlerOnChannel:(NSString*)channel
1337 taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
1340 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(
channel.UTF8String,
1342 return [
self.connections acquireConnectionForChannel:channel];
1344 NSAssert(!
handler,
@"Setting a message handler before the FlutterEngine has been run.");
1346 return [FlutterConnectionCollection makeErrorConnectionWithErrorCode:-1L];
1352 NSString*
channel = [
self.connections cleanupConnectionWithID:connection];
1354 self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(
channel.UTF8String, nil,
1360#pragma mark - FlutterTextureRegistry
1364 int64_t textureId =
self.nextTextureId++;
1365 self.platformView->RegisterExternalTexture(textureId,
texture);
1369- (void)unregisterTexture:(int64_t)textureId {
1370 _shell->GetPlatformView()->UnregisterTexture(textureId);
1373- (void)textureFrameAvailable:(int64_t)textureId {
1374 _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId);
1377- (NSString*)lookupKeyForAsset:(NSString*)asset {
1381- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
1385- (
id<FlutterPluginRegistry>)pluginRegistry {
1389#pragma mark - FlutterPluginRegistry
1391- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
1392 NSAssert(
self.pluginPublications[pluginKey] == nil,
@"Duplicate plugin key: %@", pluginKey);
1393 self.pluginPublications[pluginKey] = [NSNull null];
1395 flutterEngine:self];
1396 self.registrars[pluginKey] = result;
1400- (NSObject<FlutterApplicationRegistrar>*)registrarForApplication:(NSString*)key {
1401 NSAssert(
self.pluginPublications[
key] == nil,
@"Duplicate key: %@",
key);
1402 self.pluginPublications[key] = [NSNull null];
1405 self.registrars[key] = result;
1409- (
BOOL)hasPlugin:(NSString*)pluginKey {
1410 return _pluginPublications[pluginKey] != nil;
1413- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
1414 return _pluginPublications[pluginKey];
1417- (void)addSceneLifeCycleDelegate:(NSObject<FlutterSceneLifeCycleDelegate>*)delegate {
1418 [
self.sceneLifeCycleDelegate addDelegate:delegate];
1421#pragma mark - Notifications
1423- (void)sceneWillEnterForeground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1424 [
self flutterWillEnterForeground:notification];
1427- (void)sceneDidEnterBackground:(NSNotification*)notification API_AVAILABLE(ios(13.0)) {
1428 [
self flutterDidEnterBackground:notification];
1431- (void)applicationWillEnterForeground:(NSNotification*)notification {
1432 [
self flutterWillEnterForeground:notification];
1435- (void)applicationDidEnterBackground:(NSNotification*)notification {
1436 [
self flutterDidEnterBackground:notification];
1439- (void)flutterWillEnterForeground:(NSNotification*)notification {
1440 [
self setIsGpuDisabled:NO];
1443- (void)flutterDidEnterBackground:(NSNotification*)notification {
1444 [
self setIsGpuDisabled:YES];
1445 [
self notifyLowMemory];
1448- (void)onMemoryWarning:(NSNotification*)notification {
1449 [
self notifyLowMemory];
1452- (void)setIsGpuDisabled:(
BOOL)value {
1457 _isGpuDisabled =
value;
1460#pragma mark - Locale updates
1462- (void)onLocaleUpdated:(NSNotification*)notification {
1464 NSMutableArray<NSString*>* localeData = [[NSMutableArray alloc] init];
1465 NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
1466 for (NSString* localeID in preferredLocales) {
1467 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1468 NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
1469 NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
1470 NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
1471 NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
1472 if (!languageCode) {
1475 [localeData addObject:languageCode];
1476 [localeData addObject:(countryCode ? countryCode : @"")];
1477 [localeData addObject:(scriptCode ? scriptCode : @"")];
1478 [localeData addObject:(variantCode ? variantCode : @"")];
1480 if (localeData.count == 0) {
1483 [
self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
1486- (void)waitForFirstFrameSync:(NSTimeInterval)timeout
1487 callback:(NS_NOESCAPE
void (^_Nonnull)(
BOOL didTimeout))callback {
1493- (void)waitForFirstFrame:(NSTimeInterval)timeout
1494 callback:(
void (^_Nonnull)(
BOOL didTimeout))callback {
1495 dispatch_queue_t
queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
1496 dispatch_group_t group = dispatch_group_create();
1499 __block
BOOL didTimeout = NO;
1500 dispatch_group_async(group,
queue, ^{
1512 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
1531 libraryURI:( NSString*)libraryURI
1532 initialRoute:( NSString*)initialRoute
1533 entrypointArgs:( NSArray<NSString*>*)entrypointArgs {
1534 NSAssert(
_shell,
@"Spawning from an engine without a shell (possibly not run).");
1536 project:self.dartProject
1537 allowHeadlessExecution:self.allowHeadlessExecution];
1539 [
self.dartProject runConfigurationForEntrypoint:entrypoint
1540 libraryOrNil:libraryURI
1541 entrypointArgs:entrypointArgs];
1543 configuration.
SetEngineId(result.engineIdentifier);
1550 std::shared_ptr<flutter::IOSContext> context = ios_platform_view->
GetIosContext();
1557 [result recreatePlatformViewsController];
1558 result.platformViewsController.taskRunner = shell.GetTaskRunners().GetPlatformTaskRunner();
1559 return std::make_unique<flutter::PlatformViewIOS>(
1560 shell, context, result.platformViewsController, shell.GetTaskRunners());
1564 [](
flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell); };
1566 std::string cppInitialRoute;
1568 cppInitialRoute = [initialRoute UTF8String];
1571 std::unique_ptr<flutter::Shell> shell =
_shell->Spawn(
1572 std::move(configuration), cppInitialRoute, on_create_platform_view, on_create_rasterizer);
1574 result->_threadHost = _threadHost;
1576 result->_isGpuDisabled = _isGpuDisabled;
1577 [result setUpShell:std::move(shell) withVMServicePublication:NO];
1581- (const
flutter::ThreadHost&)threadHost {
1582 return *_threadHost;
1586 return self.dartProject;
1589- (void)sendDeepLinkToFramework:(NSURL*)url completionHandler:(
void (^)(
BOOL success))completion {
1591 [
self waitForFirstFrame:3.0
1592 callback:^(BOOL didTimeout) {
1595 logError:@"Timeout waiting for first frame when launching a URL."];
1599 [weakSelf.navigationChannel
1600 invokeMethod:@"pushRouteInformation"
1602 @"location" : url.absoluteString ?: [NSNull null],
1604 result:^(id _Nullable result) {
1606 [result isKindOfClass:[NSNumber class]] && [result boolValue];
1610 logError:@"Failed to handle route information in Flutter."];
1612 completion(success);
1622- (instancetype)initWithKey:(NSString*)key flutterEngine:(
FlutterEngine*)flutterEngine {
1623 self = [
super init];
1624 NSAssert(
self,
@"Super init cannot be nil");