28
28
29
29
static NSString *kUserNotificationWillPresentSelectorString =
30
30
@" userNotificationCenter:willPresentNotification:withCompletionHandler:" ;
31
+ static NSString *kUserNotificationDidReceiveResponseSelectorString =
32
+ @" userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:" ;
31
33
32
34
@interface FIRMessagingRemoteNotificationsProxy ()
33
35
@@ -219,10 +221,26 @@ - (void)swizzleUserNotificationCenterDelegate:(id)delegate {
219
221
if ([delegate conformsToProtocol: userNotificationCenterProtocol]) {
220
222
SEL willPresentNotificationSelector =
221
223
NSSelectorFromString (kUserNotificationWillPresentSelectorString );
222
- [self swizzleSelector: willPresentNotificationSelector
223
- inClass: [delegate class ]
224
- withImplementation: (IMP )FCM_swizzle_willPresentNotificationWithHandler
225
- inProtocol: userNotificationCenterProtocol];
224
+ // Swizzle the optional method
225
+ // "userNotificationCenter:willPresentNotification:withCompletionHandler:", if it is
226
+ // implemented. Do not swizzle otherwise, as an implementation *will* be created, which will
227
+ // fool iOS into thinking that this method is implemented, and therefore not send notifications
228
+ // to the fallback method in the app delegate
229
+ // "application:didReceiveRemoteNotification:fetchCompletionHandler:".
230
+ if ([delegate respondsToSelector: willPresentNotificationSelector]) {
231
+ [self swizzleSelector: willPresentNotificationSelector
232
+ inClass: [delegate class ]
233
+ withImplementation: (IMP )FCM_swizzle_willPresentNotificationWithHandler
234
+ inProtocol: userNotificationCenterProtocol];
235
+ }
236
+ SEL didReceiveNotificationResponseSelector =
237
+ NSSelectorFromString (kUserNotificationDidReceiveResponseSelectorString );
238
+ if ([delegate respondsToSelector: didReceiveNotificationResponseSelector]) {
239
+ [self swizzleSelector: didReceiveNotificationResponseSelector
240
+ inClass: [delegate class ]
241
+ withImplementation: (IMP )FCM_swizzle_didReceiveNotificationResponseWithHandler
242
+ inProtocol: userNotificationCenterProtocol];
243
+ }
226
244
self.currentUserNotificationCenterDelegate = delegate;
227
245
self.hasSwizzledUserNotificationDelegate = YES ;
228
246
}
@@ -235,6 +253,7 @@ - (void)unswizzleUserNotificationCenterDelegate:(id)delegate {
235
253
}
236
254
SEL willPresentNotificationSelector =
237
255
NSSelectorFromString (kUserNotificationWillPresentSelectorString );
256
+ // Call unswizzle methods, even if the method was not implemented (it will fail gracefully).
238
257
[self unswizzleSelector: willPresentNotificationSelector
239
258
inClass: [self .currentUserNotificationCenterDelegate class ]];
240
259
self.currentUserNotificationCenterDelegate = nil ;
@@ -526,25 +545,106 @@ void FCM_swizzle_willPresentNotificationWithHandler(
526
545
return ;
527
546
}
528
547
529
- // Valid original method signature, go ahead to swizzle.
548
+ // Attempt to access the user info
549
+ id notificationUserInfo = userInfoFromNotification (notification);
550
+
551
+ if (!notificationUserInfo) {
552
+ // Could not access notification.request.content.userInfo.
553
+ callOriginalMethodIfAvailable ();
554
+ return ;
555
+ }
556
+
557
+ [[FIRMessaging messaging ] appDidReceiveMessage: notificationUserInfo];
558
+ // Execute the original implementation.
559
+ callOriginalMethodIfAvailable ();
560
+ }
561
+
562
+ /* *
563
+ * Swizzle the notification handler for iOS 10+ devices.
564
+ * Signature of original handler is as below:
565
+ * - (void)userNotificationCenter:(UNUserNotificationCenter *)center
566
+ * didReceiveNotificationResponse:(UNNotificationResponse *)response
567
+ * withCompletionHandler:(void (^)(void))completionHandler
568
+ * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
569
+ * parameter types from the swizzling implementation.
570
+ */
571
+ void FCM_swizzle_didReceiveNotificationResponseWithHandler (
572
+ id self, SEL _cmd, id center, id response, void (^handler)()) {
573
+
574
+ FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy ];
575
+ IMP original_imp = [proxy originalImplementationForSelector: _cmd ];
576
+
577
+ void (^callOriginalMethodIfAvailable)() = ^{
578
+ if (original_imp) {
579
+ ((void (*)(id , SEL , id , id , void (^)(void )))original_imp)(
580
+ self, _cmd, center, response, handler);
581
+ }
582
+ return ;
583
+ };
584
+
585
+ Class notificationCenterClass = NSClassFromString (@" UNUserNotificationCenter" );
586
+ Class responseClass = NSClassFromString (@" UNNotificationResponse" );
587
+ if (!center || ![center isKindOfClass: [notificationCenterClass class ]]) {
588
+ // Invalid parameter type from the original method.
589
+ // Do not swizzle, just execute the original method.
590
+ callOriginalMethodIfAvailable ();
591
+ return ;
592
+ }
593
+
594
+ if (!response || ![response isKindOfClass: [responseClass class ]]) {
595
+ // Invalid parameter type from the original method.
596
+ // Do not swizzle, just execute the original method.
597
+ callOriginalMethodIfAvailable ();
598
+ return ;
599
+ }
600
+
601
+ if (!handler) {
602
+ // Invalid parameter type from the original method.
603
+ // Do not swizzle, just execute the original method.
604
+ callOriginalMethodIfAvailable ();
605
+ return ;
606
+ }
607
+
608
+ // Try to access the response.notification property
609
+ SEL notificationSelector = NSSelectorFromString (@" notification" );
610
+ if (![response respondsToSelector: notificationSelector]) {
611
+ // Cannot access the .notification property.
612
+ callOriginalMethodIfAvailable ();
613
+ return ;
614
+ }
615
+ id notificationClass = NSClassFromString (@" UNNotification" );
616
+ id notification = getNamedPropertyFromObject (response, @" notification" , notificationClass);
617
+
618
+ // With a notification object, use the common code to reach deep into notification
619
+ // (notification.request.content.userInfo)
620
+ id notificationUserInfo = userInfoFromNotification (notification);
621
+ if (!notificationUserInfo) {
622
+ // Could not access notification.request.content.userInfo.
623
+ callOriginalMethodIfAvailable ();
624
+ return ;
625
+ }
626
+
627
+ [[FIRMessaging messaging ] appDidReceiveMessage: notificationUserInfo];
628
+ // Execute the original implementation.
629
+ callOriginalMethodIfAvailable ();
630
+ }
631
+
632
+ id userInfoFromNotification (id notification) {
633
+
530
634
// Select the userInfo field from UNNotification.request.content.userInfo.
531
635
SEL requestSelector = NSSelectorFromString (@" request" );
532
636
if (![notification respondsToSelector: requestSelector]) {
533
- // This is not the expected notification handler. Do not swizzle, just execute the original
534
- // method.
535
- callOriginalMethodIfAvailable ();
536
- return ;
637
+ // Cannot access the request property.
638
+ return nil ;
537
639
}
538
640
Class requestClass = NSClassFromString (@" UNNotificationRequest" );
539
641
id notificationRequest = getNamedPropertyFromObject (notification, @" request" , requestClass);
540
642
541
643
SEL notificationContentSelector = NSSelectorFromString (@" content" );
542
644
if (!notificationRequest
543
645
|| ![notificationRequest respondsToSelector: notificationContentSelector]) {
544
- // This is not the expected notification handler. Do not swizzle, just execute the original
545
- // method.
546
- callOriginalMethodIfAvailable ();
547
- return ;
646
+ // Cannot access the content property.
647
+ return nil ;
548
648
}
549
649
Class contentClass = NSClassFromString (@" UNNotificationContent" );
550
650
id notificationContent = getNamedPropertyFromObject (notificationRequest,
@@ -554,25 +654,19 @@ void FCM_swizzle_willPresentNotificationWithHandler(
554
654
SEL notificationUserInfoSelector = NSSelectorFromString (@" userInfo" );
555
655
if (!notificationContent
556
656
|| ![notificationContent respondsToSelector: notificationUserInfoSelector]) {
557
- // This is not the expected notification handler. Do not swizzle, just execute the original
558
- // method.
559
- callOriginalMethodIfAvailable ();
560
- return ;
657
+ // Cannot access the userInfo property.
658
+ return nil ;
561
659
}
562
660
id notificationUserInfo = getNamedPropertyFromObject (notificationContent,
563
661
@" userInfo" ,
564
662
[NSDictionary class ]);
565
663
566
664
if (!notificationUserInfo) {
567
- // This is not the expected notification handler. Do not swizzle, just execute the original
568
- // method.
569
- callOriginalMethodIfAvailable ();
570
- return ;
665
+ // This is not the expected notification handler.
666
+ return nil ;
571
667
}
572
668
573
- [[FIRMessaging messaging ] appDidReceiveMessage: notificationUserInfo];
574
- // Execute the original implementation.
575
- callOriginalMethodIfAvailable ();
669
+ return notificationUserInfo;
576
670
}
577
671
578
672
void FCM_swizzle_applicationReceivedRemoteMessage (
0 commit comments