From 47764aab3e2dbdee683d60a3a5df32a8771c5123 Mon Sep 17 00:00:00 2001 From: akiselev-pushwoosh Date: Thu, 30 Nov 2023 14:44:54 +0100 Subject: [PATCH] [feature][SDK-197] UNUserNotificationCenterDelegate for cordova plugin --- src/ios/PushNotification.m | 142 ++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/src/ios/PushNotification.m b/src/ios/PushNotification.m index fdb35479..4f9b6669 100755 --- a/src/ios/PushNotification.m +++ b/src/ios/PushNotification.m @@ -15,6 +15,7 @@ #import #import #import +#import #import #import "PWBackward.h" @@ -78,6 +79,15 @@ void pushwoosh_swizzle(Class class, SEL fromChange, SEL toChange, IMP impl, cons @implementation PushNotification +API_AVAILABLE(ios(10)) +__weak id _originalNotificationCenterDelegate; +API_AVAILABLE(ios(10)) + struct { + unsigned int willPresentNotification : 1; + unsigned int didReceiveNotificationResponse : 1; + unsigned int openSettingsForNotification : 1; + } _originalNotificationCenterDelegateResponds; + #pragma clang diagnostic pop - (void)pluginInitialize { @@ -141,7 +151,33 @@ - (void)onDeviceReady:(CDVInvokedUrlCommand *)command { [PushNotificationManager initializeWithAppCode:appid appName:appname]; } - [UNUserNotificationCenter currentNotificationCenter].delegate = [PushNotificationManager pushManager].notificationCenterDelegate; + if (@available(iOS 10, *)) { + BOOL shouldReplaceDelegate = YES; + UNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter]; + + if (notificationCenter.delegate != nil) { + if (shouldReplaceDelegate) { + _originalNotificationCenterDelegate = notificationCenter.delegate; + _originalNotificationCenterDelegateResponds.openSettingsForNotification = + (unsigned int)[_originalNotificationCenterDelegate + respondsToSelector:@selector(userNotificationCenter:openSettingsForNotification:)]; + _originalNotificationCenterDelegateResponds.willPresentNotification = + (unsigned int)[_originalNotificationCenterDelegate + respondsToSelector:@selector(userNotificationCenter: + willPresentNotification:withCompletionHandler:)]; + _originalNotificationCenterDelegateResponds.didReceiveNotificationResponse = + (unsigned int)[_originalNotificationCenterDelegate + respondsToSelector:@selector(userNotificationCenter: + didReceiveNotificationResponse:withCompletionHandler:)]; + } + } + + if (shouldReplaceDelegate) { + __strong PushNotification *strongSelf = (PushNotification *)self; + notificationCenter.delegate = (id)strongSelf; + } + } + [self.pushManager sendAppOpen]; NSString * alertTypeString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Pushwoosh_ALERT_TYPE"]; @@ -160,6 +196,110 @@ - (void)onDeviceReady:(CDVInvokedUrlCommand *)command { [[NSUserDefaults standardUserDefaults] synchronize]; } +#pragma mark - UNUserNotificationCenter Delegate Methods +#pragma mark - + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center + willPresentNotification:(UNNotification *)notification + withCompletionHandler: +(void (^)(UNNotificationPresentationOptions options))completionHandler +API_AVAILABLE(ios(10.0)) { + + if ([self isRemoteNotification:notification] && [PWMessage isPushwooshMessage:notification.request.content.userInfo]) { + UNMutableNotificationContent *content = notification.request.content.mutableCopy; + + NSMutableDictionary *userInfo = content.userInfo.mutableCopy; + userInfo[@"pw_push"] = @(YES); + + content.userInfo = userInfo; + + //newsstand push + if (![self isContentAvailablePush:userInfo]) { + [[Pushwoosh sharedInstance] handlePushReceived:[self pushPayloadFromContent:content]]; + } + + completionHandler(UNNotificationPresentationOptionNone); + } else if ([PushNotificationManager pushManager].showPushnotificationAlert || [notification.request.content.userInfo objectForKey:@"pw_push"] == nil) { + completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); + } else { + completionHandler(UNNotificationPresentationOptionNone); + } + + if (_originalNotificationCenterDelegate != nil && + _originalNotificationCenterDelegateResponds.willPresentNotification) { + [_originalNotificationCenterDelegate userNotificationCenter:center + willPresentNotification:notification + withCompletionHandler:completionHandler]; + } +} + +- (BOOL)isContentAvailablePush:(NSDictionary *)userInfo { + NSDictionary *apsDict = userInfo[@"aps"]; + return apsDict[@"content-available"] != nil; +} + +- (NSDictionary *)pushPayloadFromContent:(UNNotificationContent *)content { + return [[content.userInfo objectForKey:@"pw_push"] isKindOfClass:[NSDictionary class]] ? [content.userInfo objectForKey:@"pw_push"] : content.userInfo; +} + +- (BOOL)isRemoteNotification:(UNNotification *)notification { + return [notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]; +} + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center +didReceiveNotificationResponse:(UNNotificationResponse *)response + withCompletionHandler:(void (^)(void))completionHandler +API_AVAILABLE(ios(10.0)) { + dispatch_block_t handlePushAcceptanceBlock = ^{ + if (![response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) { + if (![response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier] && [[PushNotificationManager pushManager].delegate respondsToSelector:@selector(onActionIdentifierReceived:withNotification:)]) { + [[PushNotificationManager pushManager].delegate onActionIdentifierReceived:response.actionIdentifier withNotification:[self pushPayloadFromContent:response.notification.request.content]]; + } + + [[Pushwoosh sharedInstance] handlePushReceived:[self pushPayloadFromContent:response.notification.request.content]]; + } + }; + + if ([self isRemoteNotification:response.notification] && [PWMessage isPushwooshMessage:response.notification.request.content.userInfo]) { + if (![self isContentAvailablePush:response.notification.request.content.userInfo]) { + [[Pushwoosh sharedInstance] handlePushReceived:[self pushPayloadFromContent:response.notification.request.content]]; + } + + handlePushAcceptanceBlock(); + } else if ([response.notification.request.content.userInfo objectForKey:@"pw_push"]) { + handlePushAcceptanceBlock(); + } + + if (_originalNotificationCenterDelegate != nil && + _originalNotificationCenterDelegateResponds.didReceiveNotificationResponse) { + [_originalNotificationCenterDelegate userNotificationCenter:center + didReceiveNotificationResponse:response + withCompletionHandler:completionHandler]; + } else { + completionHandler(); + } +} + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center + openSettingsForNotification:(nullable UNNotification *)notification +API_AVAILABLE(ios(10.0)) { + if ([[PushNotificationManager pushManager].delegate respondsToSelector:@selector(pushManager:openSettingsForNotification:)]) { + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpartial-availability" + [[PushNotificationManager pushManager].delegate pushManager:[PushNotificationManager pushManager] openSettingsForNotification:notification]; + #pragma clang diagnostic pop + } + + if (_originalNotificationCenterDelegate != nil && + _originalNotificationCenterDelegateResponds.openSettingsForNotification) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + [_originalNotificationCenterDelegate userNotificationCenter:center + openSettingsForNotification:notification]; +#pragma clang diagnostic pop + } +} + // Authorization options in addition to UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay. Should be called before registering for pushes - (void)additionalAuthorizationOptions:(CDVInvokedUrlCommand *)command { NSDictionary *options = [command.arguments firstObject];