9#import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
19 @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
20 @selector(application:performFetchWithCompletionHandler:)};
23- (void)handleDidEnterBackground:(NSNotification*)notification
24 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
25- (void)handleWillEnterForeground:(NSNotification*)notification
26 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
27- (void)handleWillResignActive:(NSNotification*)notification
28 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
29- (void)handleDidBecomeActive:(NSNotification*)notification
30 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
31- (void)handleWillTerminate:(NSNotification*)notification
32 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
34@property(nonatomic, assign)
BOOL didForwardApplicationWillLaunch;
35@property(nonatomic, assign)
BOOL didForwardApplicationDidLaunch;
39 UIBackgroundTaskIdentifier _debugBackgroundTask;
45- (void)addObserverFor:(NSString*)name selector:(
SEL)selector {
46 [[NSNotificationCenter defaultCenter] addObserver:self selector:selector name:name object:nil];
50 if (
self = [super init]) {
54 [
self addObserverFor:UIApplicationDidEnterBackgroundNotification
55 selector:@selector(handleDidEnterBackground:)];
56 [
self addObserverFor:UIApplicationWillEnterForegroundNotification
57 selector:@selector(handleWillEnterForeground:)];
58 [
self addObserverFor:UIApplicationWillResignActiveNotification
59 selector:@selector(handleWillResignActive:)];
60 [
self addObserverFor:UIApplicationDidBecomeActiveNotification
61 selector:@selector(handleDidBecomeActive:)];
62 [
self addObserverFor:UIApplicationWillTerminateNotification
63 selector:@selector(handleWillTerminate:)];
65 _delegates = [NSPointerArray weakObjectsPointerArray];
66 _debugBackgroundTask = UIBackgroundTaskInvalid;
71static BOOL IsPowerOfTwo(NSUInteger
x) {
72 return x != 0 && (
x & (
x - 1)) == 0;
75- (
BOOL)isSelectorAddedDynamically:(
SEL)selector {
77 if (selector == aSelector) {
84- (
BOOL)hasPluginThatRespondsToSelector:(
SEL)selector {
85 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
89 if ([delegate respondsToSelector:selector]) {
96- (
BOOL)appSupportsSceneLifecycle {
105- (
BOOL)pluginSupportsSceneLifecycle:(NSObject<FlutterApplicationLifeCycleDelegate>*)delegate {
111 return [delegate conformsToProtocol:@protocol(FlutterSceneLifeCycleDelegate)];
114- (void)addDelegate:(NSObject<FlutterApplicationLifeCycleDelegate>*)delegate {
115 [_delegates addPointer:(__bridge void*)delegate];
117 [_delegates compact];
121- (void)sceneFallbackDidFinishLaunchingApplication:(UIApplication*)application {
124 if (
self.didForwardApplicationDidLaunch) {
128 [
self application:application didFinishLaunchingWithOptions:@{}];
131- (void)sceneFallbackWillFinishLaunchingApplication:(UIApplication*)application {
134 if (
self.didForwardApplicationWillLaunch) {
139 if (
self.didForwardApplicationDidLaunch) {
143 [
self application:application willFinishLaunchingWithOptions:@{}];
146- (
BOOL)application:(UIApplication*)application
147 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
149 self.didForwardApplicationDidLaunch = YES;
151 return [
self application:application
152 didFinishLaunchingWithOptions:launchOptions
153 isFallbackForScene:NO];
156- (
BOOL)sceneWillConnectFallback:(UISceneConnectionOptions*)connectionOptions {
161 NSDictionary<UIApplicationLaunchOptionsKey, id>* convertedLaunchOptions =
162 ConvertConnectionOptions(connectionOptions);
163 if (convertedLaunchOptions.count == 0) {
167 if (![
self application:application
168 didFinishLaunchingWithOptions:convertedLaunchOptions
169 isFallbackForScene:YES]) {
175- (
BOOL)application:(UIApplication*)application
176 didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
177 isFallbackForScene:(
BOOL)isFallback {
180 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
181 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
184 if ([delegate respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]) {
185 if (![delegate application:application didFinishLaunchingWithOptions:launchOptions]) {
203static NSDictionary<UIApplicationLaunchOptionsKey, id>* ConvertConnectionOptions(
204 UISceneConnectionOptions* connectionOptions) {
205 NSMutableDictionary<UIApplicationLaunchOptionsKey, id>* convertedOptions =
206 [NSMutableDictionary dictionary];
208 if (connectionOptions.shortcutItem) {
209 convertedOptions[UIApplicationLaunchOptionsShortcutItemKey] = connectionOptions.shortcutItem;
211 if (connectionOptions.sourceApplication) {
212 convertedOptions[UIApplicationLaunchOptionsSourceApplicationKey] =
213 connectionOptions.sourceApplication;
215 if (connectionOptions.URLContexts.anyObject.URL) {
216 convertedOptions[UIApplicationLaunchOptionsURLKey] =
217 connectionOptions.URLContexts.anyObject.URL;
219 return convertedOptions;
222- (
BOOL)application:(UIApplication*)application
223 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
225 self.didForwardApplicationWillLaunch = YES;
228 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
232 if ([delegate respondsToSelector:_cmd]) {
233 if (![delegate application:application willFinishLaunchingWithOptions:launchOptions]) {
241- (void)handleDidEnterBackground:(NSNotification*)notification
242 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
243 if ([
self appSupportsSceneLifecycle]) {
246 UIApplication* application = [UIApplication sharedApplication];
247#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
253 _debugBackgroundTask = [application
254 beginBackgroundTaskWithName:@"Flutter debug task"
256 if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
257 [application endBackgroundTask:_debugBackgroundTask];
258 _debugBackgroundTask = UIBackgroundTaskInvalid;
261 logWarning:@"\nThe OS has terminated the Flutter debug connection for being "
262 "inactive in the background for too long.\n\n"
263 "There are no errors with your Flutter application.\n\n"
264 "To reconnect, launch your application again via 'flutter run'"];
267 [
self applicationDidEnterBackground:application isFallbackForScene:NO];
270- (void)sceneDidEnterBackgroundFallback {
275 [
self applicationDidEnterBackground:application isFallbackForScene:YES];
278- (void)applicationDidEnterBackground:(UIApplication*)application
279 isFallbackForScene:(
BOOL)isFallback {
280 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
281 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
284 if ([delegate respondsToSelector:@selector(applicationDidEnterBackground:)]) {
285 [delegate applicationDidEnterBackground:application];
290- (void)handleWillEnterForeground:(NSNotification*)notification
291 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
292 if ([
self appSupportsSceneLifecycle]) {
295 UIApplication* application = [UIApplication sharedApplication];
296#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
297 if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
298 [application endBackgroundTask:_debugBackgroundTask];
299 _debugBackgroundTask = UIBackgroundTaskInvalid;
302 [
self applicationWillEnterForeground:application isFallbackForScene:NO];
305- (void)sceneWillEnterForegroundFallback {
310 [
self applicationWillEnterForeground:application isFallbackForScene:YES];
313- (void)applicationWillEnterForeground:(UIApplication*)application
314 isFallbackForScene:(
BOOL)isFallback {
315 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
316 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
319 if ([delegate respondsToSelector:@selector(applicationWillEnterForeground:)]) {
320 [delegate applicationWillEnterForeground:application];
325- (void)handleWillResignActive:(NSNotification*)notification
326 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
327 if ([
self appSupportsSceneLifecycle]) {
330 UIApplication* application = [UIApplication sharedApplication];
331 [
self applicationWillResignActive:application isFallbackForScene:NO];
334- (void)sceneWillResignActiveFallback {
339 [
self applicationWillResignActive:application isFallbackForScene:YES];
342- (void)applicationWillResignActive:(UIApplication*)application
343 isFallbackForScene:(
BOOL)isFallback {
344 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
345 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
348 if ([delegate respondsToSelector:@selector(applicationWillResignActive:)]) {
349 [delegate applicationWillResignActive:application];
354- (void)handleDidBecomeActive:(NSNotification*)notification
355 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
356 if ([
self appSupportsSceneLifecycle]) {
359 UIApplication* application = [UIApplication sharedApplication];
360 [
self applicationDidBecomeActive:application isFallbackForScene:NO];
363- (void)sceneDidBecomeActiveFallback {
368 [
self applicationDidBecomeActive:application isFallbackForScene:YES];
371- (void)applicationDidBecomeActive:(UIApplication*)application isFallbackForScene:(
BOOL)isFallback {
372 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
373 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
376 if ([delegate respondsToSelector:@selector(applicationDidBecomeActive:)]) {
377 [delegate applicationDidBecomeActive:application];
382- (void)handleWillTerminate:(NSNotification*)notification
383 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
384 UIApplication* application = [UIApplication sharedApplication];
385 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
389 if ([delegate respondsToSelector:@selector(applicationWillTerminate:)]) {
390 [delegate applicationWillTerminate:application];
395#pragma GCC diagnostic push
396#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
397- (void)application:(UIApplication*)application
398 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
399 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
403 if ([delegate respondsToSelector:_cmd]) {
404 [delegate application:application didRegisterUserNotificationSettings:notificationSettings];
408#pragma GCC diagnostic pop
410- (void)application:(UIApplication*)application
411 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
412 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
416 if ([delegate respondsToSelector:_cmd]) {
417 [delegate application:application
418 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
423- (void)application:(UIApplication*)application
424 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
425 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
429 if ([delegate respondsToSelector:_cmd]) {
430 [delegate application:application didFailToRegisterForRemoteNotificationsWithError:error];
435- (void)application:(UIApplication*)application
436 didReceiveRemoteNotification:(NSDictionary*)userInfo
437 fetchCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
438 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
442 if ([delegate respondsToSelector:_cmd]) {
443 if ([delegate application:application
444 didReceiveRemoteNotification:userInfo
445 fetchCompletionHandler:completionHandler]) {
452#pragma GCC diagnostic push
453#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
454- (void)application:(UIApplication*)application
455 didReceiveLocalNotification:(UILocalNotification*)notification {
456 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
460 if ([delegate respondsToSelector:_cmd]) {
461 [delegate application:application didReceiveLocalNotification:notification];
465#pragma GCC diagnostic pop
467- (void)userNotificationCenter:(UNUserNotificationCenter*)center
468 willPresentNotification:(UNNotification*)notification
469 withCompletionHandler:
470 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
471 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
472 if ([delegate respondsToSelector:_cmd]) {
473 [delegate userNotificationCenter:center
474 willPresentNotification:notification
475 withCompletionHandler:completionHandler];
480- (void)userNotificationCenter:(UNUserNotificationCenter*)center
481 didReceiveNotificationResponse:(UNNotificationResponse*)response
482 withCompletionHandler:(
void (^)(
void))completionHandler {
483 for (id<FlutterApplicationLifeCycleDelegate> delegate in
_delegates.allObjects) {
484 if ([delegate respondsToSelector:_cmd]) {
485 [delegate userNotificationCenter:center
486 didReceiveNotificationResponse:response
487 withCompletionHandler:completionHandler];
492- (
BOOL)application:(UIApplication*)application
494 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
495 return [
self application:application openURL:url options:options isFallbackForScene:NO];
498- (
BOOL)sceneFallbackOpenURLContexts:(NSSet<UIOpenURLContext*>*)URLContexts {
499 for (UIOpenURLContext* context in URLContexts) {
502 options:ConvertOptions(context.options)
503 isFallbackForScene:YES]) {
510- (
BOOL)application:(UIApplication*)application
512 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options
513 isFallbackForScene:(
BOOL)isFallback {
514 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
515 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
518 if ([delegate respondsToSelector:@selector(application:openURL:options:)]) {
519 if ([delegate application:application openURL:url options:options]) {
536static NSDictionary<UIApplicationOpenURLOptionsKey, id>* ConvertOptions(
537 UISceneOpenURLOptions* options) {
538 NSMutableDictionary<UIApplicationOpenURLOptionsKey, id>* convertedOptions =
539 [NSMutableDictionary dictionary];
540 if (options.sourceApplication) {
541 convertedOptions[UIApplicationOpenURLOptionsSourceApplicationKey] = options.sourceApplication;
543 if (options.annotation) {
544 convertedOptions[UIApplicationOpenURLOptionsAnnotationKey] = options.annotation;
546 convertedOptions[UIApplicationOpenURLOptionsOpenInPlaceKey] = @(options.openInPlace);
547 if (@available(iOS 14.5, *)) {
548 if (options.eventAttribution) {
549 convertedOptions[UIApplicationOpenURLOptionsEventAttributionKey] = options.eventAttribution;
552 return convertedOptions;
555- (
BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
556 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
560 if ([delegate respondsToSelector:_cmd]) {
561 if ([delegate application:application handleOpenURL:url]) {
569- (
BOOL)application:(UIApplication*)application
571 sourceApplication:(NSString*)sourceApplication
572 annotation:(
id)annotation {
573 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
577 if ([delegate respondsToSelector:_cmd]) {
578 if ([delegate application:application
580 sourceApplication:sourceApplication
581 annotation:annotation]) {
589- (void)application:(UIApplication*)application
590 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
591 completionHandler:(
void (^)(
BOOL succeeded))completionHandler {
592 [
self application:application
593 performActionForShortcutItem:shortcutItem
594 completionHandler:completionHandler
595 isFallbackForScene:NO];
598- (
BOOL)sceneFallbackPerformActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
599 completionHandler:(
void (^)(
BOOL succeeded))completionHandler {
604 return [
self application:application
605 performActionForShortcutItem:shortcutItem
606 completionHandler:completionHandler
607 isFallbackForScene:YES];
610- (
BOOL)application:(UIApplication*)application
611 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
612 completionHandler:(
void (^)(
BOOL succeeded))completionHandler
613 isFallbackForScene:(
BOOL)isFallback {
614 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
615 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
619 respondsToSelector:@selector(
620 application:performActionForShortcutItem:completionHandler:)]) {
621 if ([delegate application:application
622 performActionForShortcutItem:shortcutItem
623 completionHandler:completionHandler]) {
631- (
BOOL)application:(UIApplication*)application
632 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
633 completionHandler:(nonnull
void (^)())completionHandler {
634 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
638 if ([delegate respondsToSelector:_cmd]) {
639 if ([delegate application:application
640 handleEventsForBackgroundURLSession:identifier
641 completionHandler:completionHandler]) {
649- (
BOOL)application:(UIApplication*)application
650 performFetchWithCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
651 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
655 if ([delegate respondsToSelector:_cmd]) {
656 if ([delegate application:application performFetchWithCompletionHandler:completionHandler]) {
664- (
BOOL)application:(UIApplication*)application
665 continueUserActivity:(NSUserActivity*)userActivity
666 restorationHandler:(
void (^)(NSArray*))restorationHandler {
667 return [
self application:application
668 continueUserActivity:userActivity
669 restorationHandler:restorationHandler
670 isFallbackForScene:NO];
673- (
BOOL)sceneFallbackContinueUserActivity:(NSUserActivity*)userActivity {
678 return [
self application:application
679 continueUserActivity:userActivity
680 restorationHandler:nil
681 isFallbackForScene:YES];
684- (
BOOL)application:(UIApplication*)application
685 continueUserActivity:(NSUserActivity*)userActivity
686 restorationHandler:(
void (^)(NSArray*))restorationHandler
687 isFallbackForScene:(
BOOL)isFallback {
688 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates.allObjects) {
689 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
693 respondsToSelector:@selector(application:continueUserActivity:restorationHandler:)]) {
694 if ([delegate application:application
695 continueUserActivity:userActivity
696 restorationHandler:restorationHandler]) {
static const SEL kSelectorsHandledByPlugins[]
NSPointerArray * _delegates
static FLUTTER_ASSERT_ARC const char * kCallbackCacheSubDir
static void LoadCacheFromDisk()
void setCachePath:(NSString *path)
UIApplication * application
std::string JoinPaths(std::initializer_list< std::string > components)