Skip to content

Commit

Permalink
fix(ios)!: duplicate notification presentation on iOS 18.0
Browse files Browse the repository at this point in the history
  • Loading branch information
erisu committed Nov 18, 2024
1 parent b4b3ce0 commit 9992653
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/ios/PushPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ @interface PushPlugin ()
@property (nonatomic, strong) NSDictionary *launchNotification;
@property (nonatomic, strong) NSDictionary *notificationMessage;
@property (nonatomic, strong) NSMutableDictionary *handlerObj;
@property (nonatomic, strong) UNNotification *previousNotification;

@property (nonatomic, assign) BOOL isInline;
@property (nonatomic, assign) BOOL clearBadge;
Expand Down Expand Up @@ -357,6 +358,30 @@ - (void)willPresentNotification:(NSNotification *)notification {

void (^completionHandler)(UNNotificationPresentationOptions) = notification.userInfo[@"completionHandler"];

if (@available(iOS 18.0, *)) {
if (@available(iOS 18.1, *)) {
// Do nothing for iOS 18.1 and higher.
} else {
// Note: In iOS 18.0, there is a known issue where "willPresentNotification" is triggered twice for a single payload.
// The "willPresentNotification" method is normally triggered when a notification is received while the app is in the
// foreground. Due to this bug, the notification payload is delivered twice, causing the front-end to process the
// notification event twice as well. This behavior is unintended, so this block of code checks if the payload is a
// duplicate by comparing the payload content and the timestamp of when it was received.
NSLog(@"[PushPlugin] Checking for duplicate notification presentation.");
if ([self isDuplicateNotification:originalNotification]) {
NSLog(@"[PushPlugin] Duplicate notification detected; processing will be skipped.");
if (completionHandler) {
completionHandler(UNNotificationPresentationOptionNone);
}
// Cleanup to remove previous notification to remove leaks
self.previousNotification = nil;
return;
}
// If it was not duplicate, we will store it to check for the potential second notification
self.previousNotification = originalNotification;
}
}

self.notificationMessage = modifiedUserInfo;
self.isInline = YES;
[self notificationReceived];
Expand Down Expand Up @@ -763,7 +788,26 @@ - (void)checkUserHasRemoteNotificationsEnabledWithCompletionHandler:(nonnull voi
}];
}

- (BOOL)isDuplicateNotification:(UNNotification *)notification {
BOOL isDuplicate = NO;
if (self.previousNotification) {
// Extract relevant data from the current notification
NSDate *currentNotificationDate = notification.date;
NSDictionary *currentPayload = notification.request.content.userInfo;
// Extract relevant data from the previous notification
NSDate *previousNotificationDate = self.previousNotification.date;
NSDictionary *previousPayload = self.previousNotification.request.content.userInfo;
// Compare the date timestamp
BOOL isSameDate = [currentNotificationDate isEqualToDate:previousNotificationDate];
// Compare the payload content
BOOL isSamePayload = [currentPayload isEqualToDictionary:previousPayload];
isDuplicate = isSameDate && isSamePayload;
}
return isDuplicate;
}

- (void)dealloc {
self.previousNotification = nil;
self.launchNotification = nil;
self.coldstart = nil;
}
Expand Down

0 comments on commit 9992653

Please sign in to comment.