From 2d7d16a65065d82d28cc627889e5f105ac77ee0c Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Mon, 21 Nov 2022 15:07:50 +0100 Subject: [PATCH 1/3] fix(messaging, ios): prevent getInitialMessage from being null at the start of the app --- .../firebase_messaging/example/lib/main.dart | 19 +++++++++++--- .../ios/Classes/FLTFirebaseMessagingPlugin.m | 26 ++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/packages/firebase_messaging/firebase_messaging/example/lib/main.dart b/packages/firebase_messaging/firebase_messaging/example/lib/main.dart index e338960fe98a..7751f2af7144 100644 --- a/packages/firebase_messaging/firebase_messaging/example/lib/main.dart +++ b/packages/firebase_messaging/firebase_messaging/example/lib/main.dart @@ -9,14 +9,14 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:http/http.dart' as http; +import 'firebase_options.dart'; import 'message.dart'; import 'message_list.dart'; import 'permissions.dart'; import 'token_monitor.dart'; -import 'firebase_options.dart'; /// Working example of FirebaseMessaging. /// Please use this in order to verify messages are working in foreground, background & terminated state. @@ -171,11 +171,20 @@ class Application extends StatefulWidget { class _Application extends State { String? _token; + String? initialMessage; @override void initState() { super.initState(); + FirebaseMessaging.instance.getInitialMessage().then( + (value) => setState( + () { + initialMessage = value?.data.toString(); + }, + ), + ); + FirebaseMessaging.onMessage.listen(showFlutterNotification); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { @@ -289,13 +298,17 @@ class _Application extends State { child: Column( children: [ MetaCard('Permissions', Permissions()), + MetaCard('Initial Message', Text(initialMessage ?? 'None')), MetaCard( 'FCM Token', TokenMonitor((token) { _token = token; return token == null ? const CircularProgressIndicator() - : Text(token, style: const TextStyle(fontSize: 12)); + : SelectableText( + token, + style: const TextStyle(fontSize: 12), + ); }), ), ElevatedButton( diff --git a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m index ac408882fe7b..3e62c19d19dc 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m @@ -22,6 +22,13 @@ @implementation FLTFirebaseMessagingPlugin { NSObject *_registrar; NSData *_apnsToken; NSDictionary *_initialNotification; + + // Used to track if everything as been initialized before answering + // to the initialNotification request + BOOL _initialNotificationGathered; + BOOL _initialNotificationIdGathered; + FLTFirebaseMethodCallResult *_initialNotificationResult; + NSString *_initialNoticationID; NSString *_notificationOpenedAppID; @@ -43,6 +50,8 @@ - (instancetype)initWithFlutterMethodChannel:(FlutterMethodChannel *)channel andFlutterPluginRegistrar:(NSObject *)registrar { self = [super init]; if (self) { + _initialNotificationGathered = NO; + _initialNotificationIdGathered = NO; _channel = channel; _registrar = registrar; // Application @@ -109,7 +118,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutter [self ensureAPNSTokenSetting]; if ([@"Messaging#getInitialMessage" isEqualToString:call.method]) { - methodCallResult.success([self copyInitialNotification]); + if (_initialNotificationGathered && _initialNotificationIdGathered) { + methodCallResult.success([self copyInitialNotification]); + } else { + _initialNotificationResult = methodCallResult; + } } else if ([@"Messaging#deleteToken" isEqualToString:call.method]) { [self messagingDeleteToken:call.arguments withMethodCallResult:methodCallResult]; } else if ([@"Messaging#getAPNSToken" isEqualToString:call.method]) { @@ -207,6 +220,11 @@ - (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)n [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification]; _initialNoticationID = remoteNotification[@"gcm.message_id"]; } + _initialNotificationGathered = YES; + if (_initialNotificationResult != nil && _initialNotificationIdGathered) { + _initialNotificationResult.success([self copyInitialNotification]); + _initialNotificationResult = nil; + } #if TARGET_OS_OSX // For macOS we use swizzling to intercept as addApplicationDelegate does not exist on the macOS @@ -346,6 +364,12 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center [_channel invokeMethod:@"Messaging#onMessageOpenedApp" arguments:notificationDict]; } + _initialNotificationIdGathered = YES; + if (_initialNotificationResult != nil && _initialNotificationGathered) { + _initialNotificationResult.success([self copyInitialNotification]); + _initialNotificationResult = nil; + } + // Forward on to any other delegates. if (_originalNotificationCenterDelegate != nil && _originalNotificationCenterDelegateRespondsTo.didReceiveNotificationResponse) { From 1e90f4b0ad71f8d1c2a952c2e1504810865ad51c Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 22 Nov 2022 10:00:28 +0100 Subject: [PATCH 2/3] fix(messaging, ios): prevent getInitialMessage from being null at the start of the app --- .../firebase_messaging/example/lib/main.dart | 12 ++++++- .../ios/Classes/FLTFirebaseMessagingPlugin.m | 33 ++++++++----------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/firebase_messaging/firebase_messaging/example/lib/main.dart b/packages/firebase_messaging/firebase_messaging/example/lib/main.dart index 7751f2af7144..fb12919dbe76 100644 --- a/packages/firebase_messaging/firebase_messaging/example/lib/main.dart +++ b/packages/firebase_messaging/firebase_messaging/example/lib/main.dart @@ -172,6 +172,7 @@ class Application extends StatefulWidget { class _Application extends State { String? _token; String? initialMessage; + bool _resolved = false; @override void initState() { @@ -180,6 +181,7 @@ class _Application extends State { FirebaseMessaging.instance.getInitialMessage().then( (value) => setState( () { + _resolved = true; initialMessage = value?.data.toString(); }, ), @@ -298,7 +300,15 @@ class _Application extends State { child: Column( children: [ MetaCard('Permissions', Permissions()), - MetaCard('Initial Message', Text(initialMessage ?? 'None')), + MetaCard( + 'Initial Message', + Column( + children: [ + Text(_resolved ? 'Resolved' : 'Resolving'), + Text(initialMessage ?? 'None'), + ], + ), + ), MetaCard( 'FCM Token', TokenMonitor((token) { diff --git a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m index 3e62c19d19dc..e62bac9ae5c8 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m @@ -26,7 +26,6 @@ @implementation FLTFirebaseMessagingPlugin { // Used to track if everything as been initialized before answering // to the initialNotification request BOOL _initialNotificationGathered; - BOOL _initialNotificationIdGathered; FLTFirebaseMethodCallResult *_initialNotificationResult; NSString *_initialNoticationID; @@ -51,7 +50,6 @@ - (instancetype)initWithFlutterMethodChannel:(FlutterMethodChannel *)channel self = [super init]; if (self) { _initialNotificationGathered = NO; - _initialNotificationIdGathered = NO; _channel = channel; _registrar = registrar; // Application @@ -118,11 +116,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutter [self ensureAPNSTokenSetting]; if ([@"Messaging#getInitialMessage" isEqualToString:call.method]) { - if (_initialNotificationGathered && _initialNotificationIdGathered) { - methodCallResult.success([self copyInitialNotification]); - } else { _initialNotificationResult = methodCallResult; - } + [self initialNotificationCallback]; + } else if ([@"Messaging#deleteToken" isEqualToString:call.method]) { [self messagingDeleteToken:call.arguments withMethodCallResult:methodCallResult]; } else if ([@"Messaging#getAPNSToken" isEqualToString:call.method]) { @@ -219,12 +215,10 @@ - (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)n _initialNotification = [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification]; _initialNoticationID = remoteNotification[@"gcm.message_id"]; + } _initialNotificationGathered = YES; - if (_initialNotificationResult != nil && _initialNotificationIdGathered) { - _initialNotificationResult.success([self copyInitialNotification]); - _initialNotificationResult = nil; - } + [self initialNotificationCallback]; #if TARGET_OS_OSX // For macOS we use swizzling to intercept as addApplicationDelegate does not exist on the macOS @@ -348,7 +342,7 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center } } -// Called when a use interacts with a notification. +// Called when a user interacts with a notification. - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler @@ -364,12 +358,6 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center [_channel invokeMethod:@"Messaging#onMessageOpenedApp" arguments:notificationDict]; } - _initialNotificationIdGathered = YES; - if (_initialNotificationResult != nil && _initialNotificationGathered) { - _initialNotificationResult.success([self copyInitialNotification]); - _initialNotificationResult = nil; - } - // Forward on to any other delegates. if (_originalNotificationCenterDelegate != nil && _originalNotificationCenterDelegateRespondsTo.didReceiveNotificationResponse) { @@ -1026,8 +1014,7 @@ - (nullable NSDictionary *)copyInitialNotification { @synchronized(self) { // Only return if initial notification was sent when app is terminated. Also ensure that // it was the initial notification that was tapped to open the app. - if (_initialNotification != nil && - [_initialNoticationID isEqualToString:_notificationOpenedAppID]) { + if (_initialNotification != nil) { NSDictionary *initialNotificationCopy = [_initialNotification copy]; _initialNotification = nil; return initialNotificationCopy; @@ -1037,6 +1024,14 @@ - (nullable NSDictionary *)copyInitialNotification { return nil; } +- (void)initialNotificationCallback { + if (_initialNotificationGathered && + _initialNotificationResult != nil) { + _initialNotificationResult.success([self copyInitialNotification]); + _initialNotificationResult = nil; + } +} + - (NSDictionary *)NSDictionaryForNSError:(NSError *)error { NSString *code = @"unknown"; NSString *message = @"An unknown error has occurred."; From 7fe5837ecf26a169ab0ddb6a493118cdb5ec795d Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 22 Nov 2022 11:47:29 +0100 Subject: [PATCH 3/3] fix(messaging, ios): prevent getInitialMessage from being null at the start of the app --- .../ios/Classes/FLTFirebaseMessagingPlugin.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m index e62bac9ae5c8..180496e0f421 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/Classes/FLTFirebaseMessagingPlugin.m @@ -116,9 +116,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutter [self ensureAPNSTokenSetting]; if ([@"Messaging#getInitialMessage" isEqualToString:call.method]) { - _initialNotificationResult = methodCallResult; - [self initialNotificationCallback]; - + _initialNotificationResult = methodCallResult; + [self initialNotificationCallback]; + } else if ([@"Messaging#deleteToken" isEqualToString:call.method]) { [self messagingDeleteToken:call.arguments withMethodCallResult:methodCallResult]; } else if ([@"Messaging#getAPNSToken" isEqualToString:call.method]) { @@ -215,7 +215,6 @@ - (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)n _initialNotification = [FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification]; _initialNoticationID = remoteNotification[@"gcm.message_id"]; - } _initialNotificationGathered = YES; [self initialNotificationCallback]; @@ -1014,7 +1013,8 @@ - (nullable NSDictionary *)copyInitialNotification { @synchronized(self) { // Only return if initial notification was sent when app is terminated. Also ensure that // it was the initial notification that was tapped to open the app. - if (_initialNotification != nil) { + if (_initialNotification != nil && + [_initialNoticationID isEqualToString:_notificationOpenedAppID]) { NSDictionary *initialNotificationCopy = [_initialNotification copy]; _initialNotification = nil; return initialNotificationCopy; @@ -1025,8 +1025,7 @@ - (nullable NSDictionary *)copyInitialNotification { } - (void)initialNotificationCallback { - if (_initialNotificationGathered && - _initialNotificationResult != nil) { + if (_initialNotificationGathered && _initialNotificationResult != nil) { _initialNotificationResult.success([self copyInitialNotification]); _initialNotificationResult = nil; }