Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ - (void)messaging:(nonnull FIRMessaging *)messaging

- (void)setupNotificationHandlingWithRemoteNotification:
(nullable NSDictionary *)remoteNotification {
[self setupNotificationHandlingWithRemoteNotification:remoteNotification actionIdentifier:nil];
}

- (void)setupNotificationHandlingWithRemoteNotification:(nullable NSDictionary *)remoteNotification
actionIdentifier:(nullable NSString *)actionIdentifier {
// If notification handling was already set up (e.g. from
// application_onDidFinishLaunchingNotification) and we're called again (e.g. from
// scene:willConnectToSession:), only process the notification but skip delegate/swizzler
Expand All @@ -234,7 +239,8 @@ - (void)setupNotificationHandlingWithRemoteNotification:
if (_notificationHandlingSetup) {
if (remoteNotification != nil) {
_initialNotification =
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification];
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification
withActionIdentifier:actionIdentifier];
_initialNotificationID = remoteNotification[@"gcm.message_id"];
_initialNotificationGathered = YES;
[self initialNotificationCallback];
Expand All @@ -255,7 +261,8 @@ - (void)setupNotificationHandlingWithRemoteNotification:
if (remoteNotification != nil) {
// If remoteNotification exists, it is the notification that opened the app.
_initialNotification =
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification];
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification
withActionIdentifier:actionIdentifier];
_initialNotificationID = remoteNotification[@"gcm.message_id"];
_initialNotificationGathered = YES;
[self initialNotificationCallback];
Expand Down Expand Up @@ -458,12 +465,20 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
API_AVAILABLE(macos(10.14), ios(10.0)) {
NSDictionary *remoteNotification = response.notification.request.content.userInfo;
_notificationOpenedAppID = remoteNotification[@"gcm.message_id"];
NSDictionary *notificationDict =
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification
withActionIdentifier:response.actionIdentifier];

if (_initialNotification != nil &&
[_initialNotificationID isEqualToString:_notificationOpenedAppID]) {
_initialNotification = notificationDict;
[self initialNotificationCallback];
}

// We only want to handle FCM notifications and stop firing `onMessageOpenedApp()` when app is
// coming from a terminated state.
if (_notificationOpenedAppID != nil &&
![_initialNotificationID isEqualToString:_notificationOpenedAppID]) {
NSDictionary *notificationDict =
[FLTFirebaseMessagingPlugin remoteMessageUserInfoToDict:remoteNotification];
[_channel invokeMethod:@"Messaging#onMessageOpenedApp" arguments:notificationDict];
}

Expand Down Expand Up @@ -642,14 +657,17 @@ - (void)scene:(UIScene *)scene
_sceneDidConnect = YES;

NSDictionary *remoteNotification = nil;
NSString *actionIdentifier = nil;
if (connectionOptions.notificationResponse != nil) {
// User tapped the notification.
remoteNotification =
connectionOptions.notificationResponse.notification.request.content.userInfo;
actionIdentifier = connectionOptions.notificationResponse.actionIdentifier;
_notificationOpenedAppID = remoteNotification[@"gcm.message_id"];
}

[self setupNotificationHandlingWithRemoteNotification:remoteNotification];
[self setupNotificationHandlingWithRemoteNotification:remoteNotification
actionIdentifier:actionIdentifier];
}
#endif

Expand Down Expand Up @@ -960,11 +978,21 @@ + (NSDictionary *)NSDictionaryFromUNNotification:(UNNotification *)notification
}

+ (NSDictionary *)remoteMessageUserInfoToDict:(NSDictionary *)userInfo {
return [self remoteMessageUserInfoToDict:userInfo withActionIdentifier:nil];
}

+ (NSDictionary *)remoteMessageUserInfoToDict:(NSDictionary *)userInfo
withActionIdentifier:(nullable NSString *)actionIdentifier {
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
NSMutableDictionary *notification = [[NSMutableDictionary alloc] init];
NSMutableDictionary *notificationIOS = [[NSMutableDictionary alloc] init];

// message.actionIdentifier
if (actionIdentifier != nil) {
message[@"actionIdentifier"] = actionIdentifier;
}

// message.data
for (id key in userInfo) {
// message.messageId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class RemoteMessage {
const RemoteMessage(
{this.senderId,
this.category,
this.actionIdentifier,
this.collapseKey,
this.contentAvailable = false,
this.data = const <String, dynamic>{},
Expand All @@ -28,6 +29,7 @@ class RemoteMessage {
return RemoteMessage(
senderId: map['senderId'],
category: map['category'],
actionIdentifier: map['actionIdentifier'],
collapseKey: map['collapseKey'],
contentAvailable: map['contentAvailable'] ?? false,
data: map['data'] == null
Expand Down Expand Up @@ -57,6 +59,7 @@ class RemoteMessage {
return <String, dynamic>{
'senderId': senderId,
'category': category,
'actionIdentifier': actionIdentifier,
'collapseKey': collapseKey,
'contentAvailable': contentAvailable,
'data': data,
Expand All @@ -77,6 +80,9 @@ class RemoteMessage {
/// The iOS category this notification is assigned to.
final String? category;

/// The Apple notification action identifier used to open the app.
final String? actionIdentifier;

/// The collapse key a message was sent with. Used to override existing messages with the same key.
final String? collapseKey;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void main() {
mockMessageMap = {
'senderId': 'senderId',
'category': 'category',
'actionIdentifier': 'actionIdentifier',
'collapseKey': 'collapseKey',
'contentAvailable': true,
'data': {
Expand All @@ -38,6 +39,7 @@ void main() {
mockNullableMessageMap = {
'senderId': null,
'category': null,
'actionIdentifier': null,
'collapseKey': null,
'data': null,
'from': null,
Expand All @@ -55,6 +57,7 @@ void main() {

expect(message.senderId, mockMessageMap!['senderId']);
expect(message.category, mockMessageMap!['category']);
expect(message.actionIdentifier, mockMessageMap!['actionIdentifier']);
expect(message.collapseKey, mockMessageMap!['collapseKey']);
expect(message.contentAvailable, mockMessageMap!['contentAvailable']);
expect(message.data, mockMessageMap!['data']);
Expand Down Expand Up @@ -85,6 +88,8 @@ void main() {

expect(message.senderId, mockNullableMessageMap['senderId']);
expect(message.category, mockNullableMessageMap['category']);
expect(
message.actionIdentifier, mockNullableMessageMap['actionIdentifier']);
expect(message.collapseKey, mockNullableMessageMap['collapseKey']);
expect(message.contentAvailable, false);
expect(message.data, {});
Expand All @@ -105,6 +110,7 @@ void main() {
final message = RemoteMessage(
senderId: mockMessageMap!['senderId'],
category: mockMessageMap!['category'],
actionIdentifier: mockMessageMap!['actionIdentifier'],
collapseKey: mockMessageMap!['collapseKey'],
contentAvailable: mockMessageMap!['contentAvailable'],
data: mockMessageMap!['data'],
Expand All @@ -120,6 +126,7 @@ void main() {

expect(message.senderId, mockMessageMap!['senderId']);
expect(message.category, mockMessageMap!['category']);
expect(message.actionIdentifier, mockMessageMap!['actionIdentifier']);
expect(message.collapseKey, mockMessageMap!['collapseKey']);
expect(message.contentAvailable, mockMessageMap!['contentAvailable']);
expect(message.data, mockMessageMap!['data']);
Expand All @@ -141,6 +148,7 @@ void main() {
mockNullableMessageMap = {
'senderId': null,
'category': null,
'actionIdentifier': null,
'collapseKey': null,
'data': null,
'from': null,
Expand All @@ -156,6 +164,8 @@ void main() {

expect(message.senderId, mockNullableMessageMap['senderId']);
expect(message.category, mockNullableMessageMap['category']);
expect(
message.actionIdentifier, mockNullableMessageMap['actionIdentifier']);
expect(message.collapseKey, mockNullableMessageMap['collapseKey']);
expect(message.contentAvailable, false);
expect(message.data, {});
Expand All @@ -173,6 +183,7 @@ void main() {
final RemoteMessage remoteMessage = RemoteMessage(
senderId: 'senderId',
category: 'category',
actionIdentifier: 'actionIdentifier',
collapseKey: 'collapseKey',
contentAvailable: true,
data: {},
Expand All @@ -193,6 +204,7 @@ void main() {

expect(map['senderId'], remoteMessage.senderId);
expect(map['category'], remoteMessage.category);
expect(map['actionIdentifier'], remoteMessage.actionIdentifier);
expect(map['collapseKey'], remoteMessage.collapseKey);
expect(map['contentAvailable'], remoteMessage.contentAvailable);
expect(map['data'], remoteMessage.data);
Expand Down
Loading