@@ -50,9 +50,12 @@ + (void)notificationOpened:(NSDictionary*)messageDict isActive:(BOOL)isActive;
5050// - userNotificationCenter:willPresentNotification:withCompletionHandler:
5151// - Reads kOSSettingsKeyInFocusDisplayOption to respect it's setting.
5252// - userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
53- // - Used to process opening a notifications.
54- // - The presents of this selector tells iOS to no longer fire `application:didReceiveRemoteNotification:fetchCompletionHandler:`.
55- // We call this to maintain existing behavior.
53+ // - Used to process opening notifications.
54+ //
55+ // NOTE: On iOS 10, when a UNUserNotificationCenterDelegate is set, UIApplicationDelegate notification selectors no longer fire.
56+ // However, this class maintains firing of UIApplicationDelegate selectors if the app did not setup it's own UNUserNotificationCenterDelegate.
57+ // This ensures we don't produce any side effects to standard iOS API selectors.
58+ // The `callLegacyAppDeletegateSelector` selector below takes care of this backwards compatibility handling.
5659
5760@implementation swizzleUNUserNotif
5861
@@ -81,18 +84,13 @@ - (void) setOneSignalUNDelegate:(id)delegate {
8184}
8285
8386// Apple's docs - Called when a notification is delivered to a foreground app.
87+ // NOTE: iOS behavior - Calling completionHandler with 0 means userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: does not trigger.
88+ // - callLegacyAppDeletegateSelector is called from here due to this case.
8489- (void )onesignalUserNotificationCenter : (UNUserNotificationCenter *)center
8590 willPresentNotification : (UNNotification *)notification
8691 withCompletionHandler : (void (^)(UNNotificationPresentationOptions options))completionHandler {
8792 [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: @" onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: Fired!" ];
8893
89- // Depercated - [OneSignal notificationCenterDelegate] - Now handled by swizzling.
90- // Proxy to user if listening to delegate and overrides the method.
91- if ([[OneSignal notificationCenterDelegate ] respondsToSelector: @selector (userNotificationCenter:willPresentNotification:withCompletionHandler: )]) {
92- [[OneSignal notificationCenterDelegate ] userNotificationCenter: center willPresentNotification: notification withCompletionHandler: completionHandler];
93- return ;
94- }
95-
9694 // Set the completionHandler options based on the ONESIGNAL_ALERT_OPTION value.
9795 if (![[NSUserDefaults standardUserDefaults ] objectForKey: @" ONESIGNAL_ALERT_OPTION" ]) {
9896 [[NSUserDefaults standardUserDefaults ] setObject: @(OSNotificationDisplayTypeInAppAlert) forKey: @" ONESIGNAL_ALERT_OPTION" ];
@@ -108,11 +106,19 @@ - (void)onesignalUserNotificationCenter:(UNUserNotificationCenter *)center
108106 default : break ;
109107 }
110108
111- // Call notificationOpened if no alert (MSB not set)
112109 [OneSignal notificationOpened: notification.request.content.userInfo isActive: YES ];
113110
111+ // Call orginal selector if one was set.
114112 if ([self respondsToSelector: @selector (onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: )])
115113 [self onesignalUserNotificationCenter: center willPresentNotification: notification withCompletionHandler: completionHandler];
114+ // Or call a legacy AppDelegate selector
115+ else {
116+ [swizzleUNUserNotif callLegacyAppDeletegateSelector: notification
117+ isTextReply: false
118+ actionIdentifier: nil
119+ userText: nil
120+ withCompletionHandler: ^() {}];
121+ }
116122
117123 // Calling completionHandler for the following reasons:
118124 // App dev may have not implented userNotificationCenter:willPresentNotification.
@@ -129,15 +135,20 @@ - (void)onesignalUserNotificationCenter:(UNUserNotificationCenter *)center
129135
130136 [swizzleUNUserNotif processiOS10Open: response];
131137
132- // For depercated OSUserNotificationCenterDelegate
133- [swizzleUNUserNotif tunnelToDelegate: center response: response handler: completionHandler];
134-
135138 // Call orginal selector if one was set.
136139 if ([self respondsToSelector: @selector (onesignalUserNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: )])
137140 [self onesignalUserNotificationCenter: center didReceiveNotificationResponse: response withCompletionHandler: completionHandler];
138- // Or call a legacy selector AppDelegate selector
139- else if (![swizzleUNUserNotif isDismissEvent: response]) // iOS 9 did not have a dismiss event
140- [swizzleUNUserNotif callLegacyAppDeletegateSelector: response withCompletionHandler: completionHandler];
141+ // Or call a legacy AppDelegate selector
142+ // - If not a dismiss event as their isn't a iOS 9 selector for it.
143+ else if (![swizzleUNUserNotif isDismissEvent: response]) {
144+ BOOL isTextReply = [response isKindOfClass: NSClassFromString (@" UNTextInputNotificationResponse" )];
145+ NSString * userText = isTextReply ? [response valueForKey: @" userText" ] : nil ;
146+ [swizzleUNUserNotif callLegacyAppDeletegateSelector: response.notification
147+ isTextReply: isTextReply
148+ actionIdentifier: response.actionIdentifier
149+ userText: userText
150+ withCompletionHandler: completionHandler];
151+ }
141152 else
142153 completionHandler ();
143154}
@@ -163,63 +174,60 @@ + (void) processiOS10Open:(UNNotificationResponse *)response {
163174 [OneSignal notificationOpened: userInfo isActive: isActive];
164175}
165176
166- // Depercated - [OneSignal notificationCenterDelegate] - Now handled by swizzling.
167- + (BOOL )tunnelToDelegate : (id )center response : (id )response handler : (void (^)())handler {
168- if ([[OneSignal notificationCenterDelegate ] respondsToSelector: @selector (userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: )]) {
169- [[OneSignal notificationCenterDelegate ] userNotificationCenter: center didReceiveNotificationResponse: response withCompletionHandler: handler];
170- return true ;
171- }
172-
173- return false ;
174- }
175-
176177// Calls depercated pre-iOS 10 selector if one is set on the AppDelegate.
177178// Even though they are deperated in iOS 10 they should still be called in iOS 10
179+ // As long as they didn't setup their own UNUserNotificationCenterDelegate
178180// - application:didReceiveLocalNotification:
179181// - application:didReceiveRemoteNotification:fetchCompletionHandler:
180182// - application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:
181183// - application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:
182184// - application:handleActionWithIdentifier:forLocalNotification:completionHandler:
183185// - application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
184- + (void )callLegacyAppDeletegateSelector : (UNNotificationResponse *)response
186+ + (void )callLegacyAppDeletegateSelector : (UNNotification *)notification
187+ isTextReply : (BOOL )isTextReply
188+ actionIdentifier : (NSString *)actionIdentifier
189+ userText : (NSString *)userText
185190 withCompletionHandler : (void (^)())completionHandler {
191+ [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: @" callLegacyAppDeletegateSelector:withCompletionHandler: Fired!" ];
192+
186193 UIApplication *sharedApp = [UIApplication sharedApplication ];
187194
188- BOOL isTextReply = [response isKindOfClass: NSClassFromString (@" UNTextInputNotificationResponse" )];
189- BOOL isLegacyLocalNotif = [response.notification.request.trigger isKindOfClass: NSClassFromString (@" UNLegacyNotificationTrigger" )];
190- BOOL isCustomAction = ![@" com.apple.UNNotificationDefaultActionIdentifier" isEqualToString: response.actionIdentifier];
191- BOOL isRemote = [response.notification.request.trigger isKindOfClass: NSClassFromString (@" UNPushNotificationTrigger" )];
195+ // trigger is nil when UIApplication.presentLocalNotificationNow: is used.
196+ // However it will be UNLegacyNotificationTrigger when UIApplication.scheduleLocalNotification: is used
197+ BOOL isLegacyLocalNotif = !notification.request .trigger || [notification.request.trigger isKindOfClass: NSClassFromString (@" UNLegacyNotificationTrigger" )];
198+ BOOL isCustomAction = actionIdentifier && ![@" com.apple.UNNotificationDefaultActionIdentifier" isEqualToString: actionIdentifier];
199+ BOOL isRemote = [notification.request.trigger isKindOfClass: NSClassFromString (@" UNPushNotificationTrigger" )];
192200
193201 if (isLegacyLocalNotif) {
194202 UILocalNotification *localNotif = [NSClassFromString (@" UIConcreteLocalNotification" ) alloc ];
195- localNotif.alertBody = response. notification .request .content .body ;
196- localNotif.alertTitle = response. notification .request .content .title ;
197- localNotif.applicationIconBadgeNumber = [response. notification.request.content.badge integerValue ];
198- NSString * soundName = [response. notification.request.content.sound valueForKey: @" _toneFileName" ];
203+ localNotif.alertBody = notification.request .content .body ;
204+ localNotif.alertTitle = notification.request .content .title ;
205+ localNotif.applicationIconBadgeNumber = [notification.request.content.badge integerValue ];
206+ NSString * soundName = [notification.request.content.sound valueForKey: @" _toneFileName" ];
199207 if (!soundName)
200208 soundName = @" UILocalNotificationDefaultSoundName" ;
201209 localNotif.soundName = soundName;
202- localNotif.alertLaunchImage = response. notification .request .content .launchImageName ;
203- localNotif.userInfo = response. notification .request .content .userInfo ;
204- localNotif.category = response. notification .request .content .categoryIdentifier ;
210+ localNotif.alertLaunchImage = notification.request .content .launchImageName ;
211+ localNotif.userInfo = notification.request .content .userInfo ;
212+ localNotif.category = notification.request .content .categoryIdentifier ;
205213 localNotif.hasAction = true ; // Defaults to true, UNLocalNotification doesn't seem to have a flag for this.
206- localNotif.fireDate = response. notification .date ;
207- localNotif.timeZone = [response. notification.request.trigger valueForKey: @" _timeZone" ];
208- localNotif.repeatInterval = (NSCalendarUnit )[response. notification.request.trigger valueForKey: @" _repeatInterval" ];
209- localNotif.repeatCalendar = [response. notification.request.trigger valueForKey: @" _repeatCalendar" ];
214+ localNotif.fireDate = notification.date ;
215+ localNotif.timeZone = [notification.request.trigger valueForKey: @" _timeZone" ];
216+ localNotif.repeatInterval = (NSCalendarUnit )[notification.request.trigger valueForKey: @" _repeatInterval" ];
217+ localNotif.repeatCalendar = [notification.request.trigger valueForKey: @" _repeatCalendar" ];
210218 // localNotif.region =
211219 // localNotif.regionTriggersOnce =
212220
213221 if (isTextReply &&
214222 [sharedApp.delegate respondsToSelector: @selector (application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler: )]) {
215- NSDictionary * dict = @{UIUserNotificationActionResponseTypedTextKey: [response valueForKey: @" userText" ] };
216- [sharedApp.delegate application: sharedApp handleActionWithIdentifier: response. actionIdentifier forLocalNotification: localNotif withResponseInfo: dict completionHandler: ^() {
223+ NSDictionary * dict = @{UIUserNotificationActionResponseTypedTextKey: userText};
224+ [sharedApp.delegate application: sharedApp handleActionWithIdentifier: actionIdentifier forLocalNotification: localNotif withResponseInfo: dict completionHandler: ^() {
217225 completionHandler ();
218226 }];
219227 }
220228 else if (isCustomAction &&
221229 [sharedApp.delegate respondsToSelector: @selector (application:handleActionWithIdentifier:forLocalNotification:completionHandler: )])
222- [sharedApp.delegate application: sharedApp handleActionWithIdentifier: response. actionIdentifier forLocalNotification: localNotif completionHandler: ^() {
230+ [sharedApp.delegate application: sharedApp handleActionWithIdentifier: actionIdentifier forLocalNotification: localNotif completionHandler: ^() {
223231 completionHandler ();
224232 }];
225233 else if ([sharedApp.delegate respondsToSelector: @selector (application:didReceiveLocalNotification: )]) {
@@ -230,18 +238,18 @@ + (void)callLegacyAppDeletegateSelector:(UNNotificationResponse *)response
230238 completionHandler ();
231239 }
232240 else if (isRemote) {
233- NSDictionary * remoteUserInfo = response. notification .request .content .userInfo ;
241+ NSDictionary * remoteUserInfo = notification.request .content .userInfo ;
234242
235243 if (isTextReply &&
236244 [sharedApp.delegate respondsToSelector: @selector (application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler: )]) {
237- NSDictionary * responseInfo = @{UIUserNotificationActionResponseTypedTextKey: [response valueForKey: @" userText" ] };
238- [sharedApp.delegate application: sharedApp handleActionWithIdentifier: response. actionIdentifier forRemoteNotification: remoteUserInfo withResponseInfo: responseInfo completionHandler: ^() {
245+ NSDictionary * responseInfo = @{UIUserNotificationActionResponseTypedTextKey: userText};
246+ [sharedApp.delegate application: sharedApp handleActionWithIdentifier: actionIdentifier forRemoteNotification: remoteUserInfo withResponseInfo: responseInfo completionHandler: ^() {
239247 completionHandler ();
240248 }];
241249 }
242250 else if (isCustomAction &&
243251 [sharedApp.delegate respondsToSelector: @selector (application:handleActionWithIdentifier:forRemoteNotification:completionHandler: )])
244- [sharedApp.delegate application: sharedApp handleActionWithIdentifier: response. actionIdentifier forRemoteNotification: remoteUserInfo completionHandler: ^() {
252+ [sharedApp.delegate application: sharedApp handleActionWithIdentifier: actionIdentifier forRemoteNotification: remoteUserInfo completionHandler: ^() {
245253 completionHandler ();
246254 }];
247255 else if ([sharedApp.delegate respondsToSelector: @selector (application:didReceiveRemoteNotification:fetchCompletionHandler: )]) {
0 commit comments