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 {
178 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
179 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
182 if ([delegate respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]) {
183 if (![delegate application:application didFinishLaunchingWithOptions:launchOptions]) {
201static NSDictionary<UIApplicationLaunchOptionsKey, id>* ConvertConnectionOptions(
202 UISceneConnectionOptions* connectionOptions) {
203 NSMutableDictionary<UIApplicationLaunchOptionsKey, id>* convertedOptions =
204 [NSMutableDictionary dictionary];
206 if (connectionOptions.shortcutItem) {
207 convertedOptions[UIApplicationLaunchOptionsShortcutItemKey] = connectionOptions.shortcutItem;
209 if (connectionOptions.sourceApplication) {
210 convertedOptions[UIApplicationLaunchOptionsSourceApplicationKey] =
211 connectionOptions.sourceApplication;
213 if (connectionOptions.URLContexts.anyObject.URL) {
214 convertedOptions[UIApplicationLaunchOptionsURLKey] =
215 connectionOptions.URLContexts.anyObject.URL;
217 return convertedOptions;
220- (
BOOL)application:(UIApplication*)application
221 willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
223 self.didForwardApplicationWillLaunch = YES;
226 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in [
_delegates allObjects]) {
230 if ([delegate respondsToSelector:_cmd]) {
231 if (![delegate application:application willFinishLaunchingWithOptions:launchOptions]) {
239- (void)handleDidEnterBackground:(NSNotification*)notification
240 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
241 if ([
self appSupportsSceneLifecycle]) {
244 UIApplication* application = [UIApplication sharedApplication];
245#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
251 _debugBackgroundTask = [application
252 beginBackgroundTaskWithName:@"Flutter debug task"
254 if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
255 [application endBackgroundTask:_debugBackgroundTask];
256 _debugBackgroundTask = UIBackgroundTaskInvalid;
259 logWarning:@"\nThe OS has terminated the Flutter debug connection for being "
260 "inactive in the background for too long.\n\n"
261 "There are no errors with your Flutter application.\n\n"
262 "To reconnect, launch your application again via 'flutter run'"];
265 [
self applicationDidEnterBackground:application isFallbackForScene:NO];
268- (void)sceneDidEnterBackgroundFallback {
273 [
self applicationDidEnterBackground:application isFallbackForScene:YES];
276- (void)applicationDidEnterBackground:(UIApplication*)application
277 isFallbackForScene:(
BOOL)isFallback {
278 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
279 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
282 if ([delegate respondsToSelector:@selector(applicationDidEnterBackground:)]) {
283 [delegate applicationDidEnterBackground:application];
288- (void)handleWillEnterForeground:(NSNotification*)notification
289 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
290 if ([
self appSupportsSceneLifecycle]) {
293 UIApplication* application = [UIApplication sharedApplication];
294#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
295 if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
296 [application endBackgroundTask:_debugBackgroundTask];
297 _debugBackgroundTask = UIBackgroundTaskInvalid;
300 [
self applicationWillEnterForeground:application isFallbackForScene:NO];
303- (void)sceneWillEnterForegroundFallback {
308 [
self applicationWillEnterForeground:application isFallbackForScene:YES];
311- (void)applicationWillEnterForeground:(UIApplication*)application
312 isFallbackForScene:(
BOOL)isFallback {
313 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
314 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
317 if ([delegate respondsToSelector:@selector(applicationWillEnterForeground:)]) {
318 [delegate applicationWillEnterForeground:application];
323- (void)handleWillResignActive:(NSNotification*)notification
324 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
325 if ([
self appSupportsSceneLifecycle]) {
328 UIApplication* application = [UIApplication sharedApplication];
329 [
self applicationWillResignActive:application isFallbackForScene:NO];
332- (void)sceneWillResignActiveFallback {
337 [
self applicationWillResignActive:application isFallbackForScene:YES];
340- (void)applicationWillResignActive:(UIApplication*)application
341 isFallbackForScene:(
BOOL)isFallback {
342 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
343 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
346 if ([delegate respondsToSelector:@selector(applicationWillResignActive:)]) {
347 [delegate applicationWillResignActive:application];
352- (void)handleDidBecomeActive:(NSNotification*)notification
353 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
354 if ([
self appSupportsSceneLifecycle]) {
357 UIApplication* application = [UIApplication sharedApplication];
358 [
self applicationDidBecomeActive:application isFallbackForScene:NO];
361- (void)sceneDidBecomeActiveFallback {
366 [
self applicationDidBecomeActive:application isFallbackForScene:YES];
369- (void)applicationDidBecomeActive:(UIApplication*)application isFallbackForScene:(
BOOL)isFallback {
370 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
371 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
374 if ([delegate respondsToSelector:@selector(applicationDidBecomeActive:)]) {
375 [delegate applicationDidBecomeActive:application];
380- (void)handleWillTerminate:(NSNotification*)notification
381 NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
382 UIApplication* application = [UIApplication sharedApplication];
383 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
387 if ([delegate respondsToSelector:@selector(applicationWillTerminate:)]) {
388 [delegate applicationWillTerminate:application];
393#pragma GCC diagnostic push
394#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
395- (void)application:(UIApplication*)application
396 didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
397 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
401 if ([delegate respondsToSelector:_cmd]) {
402 [delegate application:application didRegisterUserNotificationSettings:notificationSettings];
406#pragma GCC diagnostic pop
408- (void)application:(UIApplication*)application
409 didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
410 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
414 if ([delegate respondsToSelector:_cmd]) {
415 [delegate application:application
416 didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
421- (void)application:(UIApplication*)application
422 didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
423 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
427 if ([delegate respondsToSelector:_cmd]) {
428 [delegate application:application didFailToRegisterForRemoteNotificationsWithError:error];
433- (void)application:(UIApplication*)application
434 didReceiveRemoteNotification:(NSDictionary*)userInfo
435 fetchCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
436 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
440 if ([delegate respondsToSelector:_cmd]) {
441 if ([delegate application:application
442 didReceiveRemoteNotification:userInfo
443 fetchCompletionHandler:completionHandler]) {
450#pragma GCC diagnostic push
451#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
452- (void)application:(UIApplication*)application
453 didReceiveLocalNotification:(UILocalNotification*)notification {
454 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
458 if ([delegate respondsToSelector:_cmd]) {
459 [delegate application:application didReceiveLocalNotification:notification];
463#pragma GCC diagnostic pop
465- (void)userNotificationCenter:(UNUserNotificationCenter*)center
466 willPresentNotification:(UNNotification*)notification
467 withCompletionHandler:
468 (
void (^)(UNNotificationPresentationOptions options))completionHandler {
469 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
470 if ([delegate respondsToSelector:_cmd]) {
471 [delegate userNotificationCenter:center
472 willPresentNotification:notification
473 withCompletionHandler:completionHandler];
478- (void)userNotificationCenter:(UNUserNotificationCenter*)center
479 didReceiveNotificationResponse:(UNNotificationResponse*)response
480 withCompletionHandler:(
void (^)(
void))completionHandler {
481 for (id<FlutterApplicationLifeCycleDelegate> delegate in
_delegates) {
482 if ([delegate respondsToSelector:_cmd]) {
483 [delegate userNotificationCenter:center
484 didReceiveNotificationResponse:response
485 withCompletionHandler:completionHandler];
490- (
BOOL)application:(UIApplication*)application
492 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options {
493 return [
self application:application openURL:url options:options isFallbackForScene:NO];
496- (
BOOL)sceneFallbackOpenURLContexts:(NSSet<UIOpenURLContext*>*)URLContexts {
497 for (UIOpenURLContext* context in URLContexts) {
500 options:ConvertOptions(context.options)
501 isFallbackForScene:YES]) {
508- (
BOOL)application:(UIApplication*)application
510 options:(NSDictionary<UIApplicationOpenURLOptionsKey,
id>*)options
511 isFallbackForScene:(
BOOL)isFallback {
512 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
513 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
516 if ([delegate respondsToSelector:@selector(application:openURL:options:)]) {
517 if ([delegate application:application openURL:url options:options]) {
534static NSDictionary<UIApplicationOpenURLOptionsKey, id>* ConvertOptions(
535 UISceneOpenURLOptions* options) {
536 NSMutableDictionary<UIApplicationOpenURLOptionsKey, id>* convertedOptions =
537 [NSMutableDictionary dictionary];
538 if (options.sourceApplication) {
539 convertedOptions[UIApplicationOpenURLOptionsSourceApplicationKey] = options.sourceApplication;
541 if (options.annotation) {
542 convertedOptions[UIApplicationOpenURLOptionsAnnotationKey] = options.annotation;
544 convertedOptions[UIApplicationOpenURLOptionsOpenInPlaceKey] = @(options.openInPlace);
545 if (@available(iOS 14.5, *)) {
546 if (options.eventAttribution) {
547 convertedOptions[UIApplicationOpenURLOptionsEventAttributionKey] = options.eventAttribution;
550 return convertedOptions;
553- (
BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
554 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
558 if ([delegate respondsToSelector:_cmd]) {
559 if ([delegate application:application handleOpenURL:url]) {
567- (
BOOL)application:(UIApplication*)application
569 sourceApplication:(NSString*)sourceApplication
570 annotation:(
id)annotation {
571 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
575 if ([delegate respondsToSelector:_cmd]) {
576 if ([delegate application:application
578 sourceApplication:sourceApplication
579 annotation:annotation]) {
587- (void)application:(UIApplication*)application
588 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
589 completionHandler:(
void (^)(
BOOL succeeded))completionHandler {
590 [
self application:application
591 performActionForShortcutItem:shortcutItem
592 completionHandler:completionHandler
593 isFallbackForScene:NO];
596- (
BOOL)sceneFallbackPerformActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
597 completionHandler:(
void (^)(
BOOL succeeded))completionHandler {
602 return [
self application:application
603 performActionForShortcutItem:shortcutItem
604 completionHandler:completionHandler
605 isFallbackForScene:YES];
608- (
BOOL)application:(UIApplication*)application
609 performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
610 completionHandler:(
void (^)(
BOOL succeeded))completionHandler
611 isFallbackForScene:(
BOOL)isFallback {
612 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
613 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
616 if ([delegate respondsToSelector:@selector(application:
617 performActionForShortcutItem:completionHandler:)]) {
618 if ([delegate application:application
619 performActionForShortcutItem:shortcutItem
620 completionHandler:completionHandler]) {
628- (
BOOL)application:(UIApplication*)application
629 handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
630 completionHandler:(nonnull
void (^)())completionHandler {
631 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
635 if ([delegate respondsToSelector:_cmd]) {
636 if ([delegate application:application
637 handleEventsForBackgroundURLSession:identifier
638 completionHandler:completionHandler]) {
646- (
BOOL)application:(UIApplication*)application
647 performFetchWithCompletionHandler:(
void (^)(UIBackgroundFetchResult result))completionHandler {
648 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
652 if ([delegate respondsToSelector:_cmd]) {
653 if ([delegate application:application performFetchWithCompletionHandler:completionHandler]) {
661- (
BOOL)application:(UIApplication*)application
662 continueUserActivity:(NSUserActivity*)userActivity
663 restorationHandler:(
void (^)(NSArray*))restorationHandler {
664 return [
self application:application
665 continueUserActivity:userActivity
666 restorationHandler:restorationHandler
667 isFallbackForScene:NO];
670- (
BOOL)sceneFallbackContinueUserActivity:(NSUserActivity*)userActivity {
675 return [
self application:application
676 continueUserActivity:userActivity
677 restorationHandler:nil
678 isFallbackForScene:YES];
681- (
BOOL)application:(UIApplication*)application
682 continueUserActivity:(NSUserActivity*)userActivity
683 restorationHandler:(
void (^)(NSArray*))restorationHandler
684 isFallbackForScene:(
BOOL)isFallback {
685 for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in
_delegates) {
686 if (!delegate || (isFallback && [
self pluginSupportsSceneLifecycle:delegate])) {
689 if ([delegate respondsToSelector:@selector(application:
690 continueUserActivity:restorationHandler:)]) {
691 if ([delegate application:application
692 continueUserActivity:userActivity
693 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)