Skip to content

How to prevent expired notification from displaying

Ivan Bilobrk edited this page Aug 29, 2025 · 2 revisions

When sending push notifications with a validity period set, it may sometimes happen that the notification is still displayed even though it has expired. This is because APNs operates as a best-effort service and does not guarantee that notifications will not be delivered after the validity period has passed.

As a workaround, you can send silent push notifications as described in API documentation. After that, in your didReceiveRemoteNotification method - either in ios/pods/MobileMessaging/Classes/MobileMessagingObjC/Core/Plugins/MobileMessagingPluginApplicationDelegate.m, or your own AppDelegate - you should check if the notification is expired and, if so, prevent it from being displayed.

Notice:

Silent notifications are not guaranteed to be delivered to the iOS device if the application is in suspended state. For more information, see Apple documentation.

An example implementation is as follows:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Check if the payload can be used to create an MM_MTMessage object.
    MM_MTMessage *message = [MM_MTMessage makeWithPayload:userInfo];
    if (message != nil) {
        NSDictionary *internalData = userInfo[@"internalData"] ?: @{};
        // Check if the notification is a silent one.
        BOOL isSilent = internalData[@"silent"] != nil;
        // Check if there are details for an in-app message.
        BOOL isNewInApp = internalData[@"inAppDetails"] != nil;

        // Check if the notification is expired.
        BOOL isExpired = NO;
        NSNumber *validUntil = internalData[@"validUntil"];
        if (validUntil != nil) {
            NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
            NSTimeInterval validUntilTime = [validUntil doubleValue] / 1000.0;
            isExpired = currentTime > validUntilTime;
        }
        
        // If the notification is expired, do not process it further and call the completion handler with no data.
        if (isExpired) {
            completionHandler(UIBackgroundFetchResultNoData);
            return;
        }

        // If the notification is silent and not in-app, show it as a local notification.
        if (isSilent && !isNewInApp) {
            [MobileMessaging scheduleUserNotificationWith:message completion:^{
                [MobileMessaging didReceiveRemoteNotification:[self extendUserInfoIfNeeded:userInfo] fetchCompletionHandler:completionHandler];
            }];
        // For non-silent or in-app messages, process them normally and pass them to the MobileMessaging SDK.
        } else {
            [MobileMessaging didReceiveRemoteNotification:[self extendUserInfoIfNeeded:userInfo] fetchCompletionHandler:completionHandler];
        }
    // If the payload does not conform to the MobileMessaging SDK model, check for a custom application delegate and forward to it, if available.
    } else if (_applicationDelegate && [_applicationDelegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
		[_applicationDelegate application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
    } else {
        completionHandler(UIBackgroundFetchResultNoData);
    }
}
Clone this wiki locally