@@ -40,6 +40,9 @@ @implementation FLTFirebaseMessagingPlugin {
4040 NSString *_notificationOpenedAppID;
4141 NSString *_foregroundUniqueIdentifier;
4242
43+ // Track if scene delegate connected (for iOS 13+ scene delegate support)
44+ BOOL _sceneDidConnect;
45+
4346#ifdef __FF_NOTIFICATIONS_SUPPORTED_PLATFORM
4447 API_AVAILABLE (ios (10 ), macosx (10.14 ))
4548 __weak id <UNUserNotificationCenterDelegate > _originalNotificationCenterDelegate;
@@ -59,6 +62,7 @@ - (instancetype)initWithFlutterMethodChannel:(FlutterMethodChannel *)channel
5962 self = [super init ];
6063 if (self) {
6164 _initialNotificationGathered = NO ;
65+ _sceneDidConnect = NO ;
6266 _channel = channel;
6367 _registrar = registrar;
6468 // Application
@@ -216,22 +220,31 @@ - (void)messaging:(nonnull FIRMessaging *)messaging
216220
217221#pragma mark - NSNotificationCenter Observers
218222
219- - (void )application_onDidFinishLaunchingNotification : (nonnull NSNotification *)notification {
220- // Setup UIApplicationDelegate.
221- #if TARGET_OS_OSX
222- NSDictionary *remoteNotification = notification.userInfo [NSApplicationLaunchUserNotificationKey ];
223- #else
224- NSDictionary *remoteNotification =
225- notification.userInfo [UIApplicationLaunchOptionsRemoteNotificationKey];
226- #endif
223+ - (void )setupNotificationHandlingWithRemoteNotification :
224+ (nullable NSDictionary *)remoteNotification {
227225 if (remoteNotification != nil ) {
228226 // If remoteNotification exists, it is the notification that opened the app.
229227 _initialNotification =
230228 [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict: remoteNotification];
231229 _initialNotificationID = remoteNotification[@" gcm.message_id" ];
230+ _initialNotificationGathered = YES ;
231+ [self initialNotificationCallback ];
232+ } else if (_sceneDidConnect) {
233+ // For scene delegates, if no notification was found in connectionOptions,
234+ // delay marking as gathered to allow didReceiveRemoteNotification to fire first
235+ // for contentAvailable notifications that caused the app to launch
236+ dispatch_after (dispatch_time (DISPATCH_TIME_NOW, (int64_t )(0.1 * NSEC_PER_SEC)),
237+ dispatch_get_main_queue (), ^{
238+ if (!self->_initialNotificationGathered ) {
239+ self->_initialNotificationGathered = YES ;
240+ [self initialNotificationCallback ];
241+ }
242+ });
243+ } else {
244+ // For non-scene delegate apps, mark as gathered immediately
245+ _initialNotificationGathered = YES ;
246+ [self initialNotificationCallback ];
232247 }
233- _initialNotificationGathered = YES ;
234- [self initialNotificationCallback ];
235248
236249 [GULAppDelegateSwizzler registerAppDelegateInterceptor: self ];
237250 [GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods ];
@@ -314,6 +327,17 @@ - (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)n
314327#endif
315328}
316329
330+ - (void )application_onDidFinishLaunchingNotification : (nonnull NSNotification *)notification {
331+ // Setup UIApplicationDelegate.
332+ #if TARGET_OS_OSX
333+ NSDictionary *remoteNotification = notification.userInfo [NSApplicationLaunchUserNotificationKey ];
334+ #else
335+ NSDictionary *remoteNotification =
336+ notification.userInfo [UIApplicationLaunchOptionsRemoteNotificationKey];
337+ #endif
338+ [self setupNotificationHandlingWithRemoteNotification: remoteNotification];
339+ }
340+
317341#pragma mark - UNUserNotificationCenter Delegate Methods
318342
319343#ifdef __FF_NOTIFICATIONS_SUPPORTED_PLATFORM
@@ -473,6 +497,15 @@ - (BOOL)application:(UIApplication *)application
473497 [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict: userInfo];
474498 // Only handle notifications from FCM.
475499 if (userInfo[@" gcm.message_id" ]) {
500+ // For scene delegate apps: if this notification arrives during cold launch
501+ // (before initial notification gathering is complete) and no notification was found
502+ // in connectionOptions, this is the notification that caused the launch.
503+ if (_sceneDidConnect && !_initialNotificationGathered && _initialNotification == nil ) {
504+ _initialNotification = notificationDict;
505+ _initialNotificationID = userInfo[@" gcm.message_id" ];
506+ _initialNotificationGathered = YES ;
507+ [self initialNotificationCallback ];
508+ }
476509 if ([UIApplication sharedApplication ].applicationState == UIApplicationStateBackground) {
477510 __block BOOL completed = NO ;
478511
@@ -538,24 +571,21 @@ - (BOOL)application:(UIApplication *)application
538571#pragma mark - SceneDelegate Methods
539572
540573#if !TARGET_OS_OSX
541- - (BOOL )scene:(UIScene *)scene
574+ - (void )scene:(UIScene *)scene
542575 willConnectToSession:(UISceneSession *)session
543576 options:(UISceneConnectionOptions *)connectionOptions {
544577 // Handle launch notification if present
545- NSDictionary *remoteNotification =
546- connectionOptions.notificationResponse .notification .request .content .userInfo ;
547- if (remoteNotification != nil ) {
548- // If remoteNotification exists, it is the notification that opened the app.
549- _initialNotification =
550- [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict: remoteNotification];
551- _initialNotificationID = remoteNotification[@" gcm.message_id" ];
578+ // With scene delegates, the notification can be in notificationResponse if user tapped it
579+ _sceneDidConnect = YES ;
580+
581+ NSDictionary *remoteNotification = nil ;
582+ if (connectionOptions.notificationResponse != nil ) {
583+ // User tapped the notification.
584+ remoteNotification =
585+ connectionOptions.notificationResponse .notification .request .content .userInfo ;
552586 }
553587
554- // Register for remote notifications in scene delegate
555- // This is critical for getting APNS token when using UISceneDelegate
556- [[UIApplication sharedApplication ] registerForRemoteNotifications ];
557-
558- return YES ;
588+ [self setupNotificationHandlingWithRemoteNotification: remoteNotification];
559589}
560590#endif
561591
0 commit comments