2 * Copyright 2017 Google
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #import "FIRMessagingRemoteNotificationsProxy.h"
19 #import <objc/runtime.h>
20 #import <UIKit/UIKit.h>
22 #import "FIRMessagingConstants.h"
23 #import "FIRMessagingLogger.h"
24 #import "FIRMessagingUtilities.h"
25 #import "FIRMessaging_Private.h"
27 static const BOOL kDefaultAutoRegisterEnabledValue = YES;
28 static void * UserNotificationObserverContext = &UserNotificationObserverContext;
30 static NSString *kUserNotificationWillPresentSelectorString =
31 @"userNotificationCenter:willPresentNotification:withCompletionHandler:";
32 static NSString *kUserNotificationDidReceiveResponseSelectorString =
33 @"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:";
34 static NSString *kReceiveDataMessageSelectorString = @"messaging:didReceiveMessage:";
36 @interface FIRMessagingRemoteNotificationsProxy ()
38 @property(strong, nonatomic) NSMutableDictionary<NSString *, NSValue *> *originalAppDelegateImps;
39 @property(strong, nonatomic) NSMutableDictionary<NSString *, NSArray *> *swizzledSelectorsByClass;
41 @property(nonatomic) BOOL didSwizzleMethods;
42 @property(nonatomic) BOOL didSwizzleAppDelegateMethods;
44 @property(nonatomic) BOOL hasSwizzledUserNotificationDelegate;
45 @property(nonatomic) BOOL isObservingUserNotificationDelegateChanges;
47 @property(strong, nonatomic) id userNotificationCenter;
48 @property(strong, nonatomic) id currentUserNotificationCenterDelegate;
52 @implementation FIRMessagingRemoteNotificationsProxy
54 + (BOOL)canSwizzleMethods {
56 [[NSBundle mainBundle]
57 objectForInfoDictionaryKey: kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey];
58 if (canSwizzleValue && [canSwizzleValue isKindOfClass:[NSNumber class]]) {
59 NSNumber *canSwizzleNumberValue = (NSNumber *)canSwizzleValue;
60 return canSwizzleNumberValue.boolValue;
62 return kDefaultAutoRegisterEnabledValue;
66 + (void)swizzleMethods {
67 [[FIRMessagingRemoteNotificationsProxy sharedProxy] swizzleMethodsIfPossible];
70 + (instancetype)sharedProxy {
71 static FIRMessagingRemoteNotificationsProxy *proxy;
72 static dispatch_once_t onceToken;
73 dispatch_once(&onceToken, ^{
74 proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
79 - (instancetype)init {
82 _originalAppDelegateImps = [[NSMutableDictionary alloc] init];
83 _swizzledSelectorsByClass = [[NSMutableDictionary alloc] init];
89 [self unswizzleAllMethods];
90 self.swizzledSelectorsByClass = nil;
91 [self.originalAppDelegateImps removeAllObjects];
92 self.originalAppDelegateImps = nil;
93 [self removeUserNotificationCenterDelegateObserver];
96 - (void)swizzleMethodsIfPossible {
98 if (self.didSwizzleMethods) {
102 UIApplication *application = FIRMessagingUIApplication();
106 NSObject<UIApplicationDelegate> *appDelegate = [application delegate];
107 [self swizzleAppDelegateMethods:appDelegate];
109 // Add KVO listener on [UNUserNotificationCenter currentNotificationCenter]'s delegate property
110 Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
111 if (notificationCenterClass) {
112 // We are linked against iOS 10 SDK or above
113 id notificationCenter = getNamedPropertyFromObject(notificationCenterClass,
114 @"currentNotificationCenter",
115 notificationCenterClass);
116 if (notificationCenter) {
117 [self listenForDelegateChangesInUserNotificationCenter:notificationCenter];
121 self.didSwizzleMethods = YES;
124 - (void)unswizzleAllMethods {
125 for (NSString *className in self.swizzledSelectorsByClass) {
126 Class klass = NSClassFromString(className);
127 NSArray *selectorStrings = self.swizzledSelectorsByClass[className];
128 for (NSString *selectorString in selectorStrings) {
129 SEL selector = NSSelectorFromString(selectorString);
130 [self unswizzleSelector:selector inClass:klass];
133 [self.swizzledSelectorsByClass removeAllObjects];
136 - (void)swizzleAppDelegateMethods:(id<UIApplicationDelegate>)appDelegate {
137 if (![appDelegate conformsToProtocol:@protocol(UIApplicationDelegate)]) {
140 Class appDelegateClass = [appDelegate class];
142 BOOL didSwizzleAppDelegate = NO;
143 // Message receiving handler for iOS 9, 8, 7 devices (both display notification and data message).
144 SEL remoteNotificationSelector =
145 @selector(application:didReceiveRemoteNotification:);
147 SEL remoteNotificationWithFetchHandlerSelector =
148 @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
150 // For recording when APNS tokens are registered (or fail to register)
151 SEL registerForAPNSFailSelector =
152 @selector(application:didFailToRegisterForRemoteNotificationsWithError:);
154 SEL registerForAPNSSuccessSelector =
155 @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);
158 // Receive Remote Notifications.
159 BOOL selectorWithFetchHandlerImplemented = NO;
160 if ([appDelegate respondsToSelector:remoteNotificationWithFetchHandlerSelector]) {
161 selectorWithFetchHandlerImplemented = YES;
162 [self swizzleSelector:remoteNotificationWithFetchHandlerSelector
163 inClass:appDelegateClass
164 withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotificationWithHandler
165 inProtocol:@protocol(UIApplicationDelegate)];
166 didSwizzleAppDelegate = YES;
169 if ([appDelegate respondsToSelector:remoteNotificationSelector] ||
170 !selectorWithFetchHandlerImplemented) {
171 [self swizzleSelector:remoteNotificationSelector
172 inClass:appDelegateClass
173 withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotification
174 inProtocol:@protocol(UIApplicationDelegate)];
175 didSwizzleAppDelegate = YES;
178 // For data message from MCS.
179 SEL receiveDataMessageSelector = NSSelectorFromString(kReceiveDataMessageSelectorString);
180 if ([appDelegate respondsToSelector:receiveDataMessageSelector]) {
181 [self swizzleSelector:receiveDataMessageSelector
182 inClass:appDelegateClass
183 withImplementation:(IMP)FCM_swizzle_messagingDidReceiveMessage
184 inProtocol:@protocol(UIApplicationDelegate)];
185 didSwizzleAppDelegate = YES;
188 // Receive APNS token
189 [self swizzleSelector:registerForAPNSSuccessSelector
190 inClass:appDelegateClass
191 withImplementation:(IMP)FCM_swizzle_appDidRegisterForRemoteNotifications
192 inProtocol:@protocol(UIApplicationDelegate)];
194 [self swizzleSelector:registerForAPNSFailSelector
195 inClass:appDelegateClass
196 withImplementation:(IMP)FCM_swizzle_appDidFailToRegisterForRemoteNotifications
197 inProtocol:@protocol(UIApplicationDelegate)];
199 self.didSwizzleAppDelegateMethods = didSwizzleAppDelegate;
202 - (void)listenForDelegateChangesInUserNotificationCenter:(id)notificationCenter {
203 Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
204 if (![notificationCenter isKindOfClass:notificationCenterClass]) {
207 id delegate = getNamedPropertyFromObject(notificationCenter, @"delegate", nil);
208 Protocol *delegateProtocol = NSProtocolFromString(@"UNUserNotificationCenterDelegate");
209 if ([delegate conformsToProtocol:delegateProtocol]) {
210 // Swizzle this object now, if available
211 [self swizzleUserNotificationCenterDelegate:delegate];
213 // Add KVO observer for "delegate" keyPath for future changes
214 [self addDelegateObserverToUserNotificationCenter:notificationCenter];
217 #pragma mark - UNNotificationCenter Swizzling
219 - (void)swizzleUserNotificationCenterDelegate:(id _Nonnull)delegate {
220 if (self.currentUserNotificationCenterDelegate == delegate) {
221 // Via pointer-check, compare if we have already swizzled this item.
224 Protocol *userNotificationCenterProtocol =
225 NSProtocolFromString(@"UNUserNotificationCenterDelegate");
226 if ([delegate conformsToProtocol:userNotificationCenterProtocol]) {
227 SEL willPresentNotificationSelector =
228 NSSelectorFromString(kUserNotificationWillPresentSelectorString);
229 // Swizzle the optional method
230 // "userNotificationCenter:willPresentNotification:withCompletionHandler:", if it is
231 // implemented. Do not swizzle otherwise, as an implementation *will* be created, which will
232 // fool iOS into thinking that this method is implemented, and therefore not send notifications
233 // to the fallback method in the app delegate
234 // "application:didReceiveRemoteNotification:fetchCompletionHandler:".
235 if ([delegate respondsToSelector:willPresentNotificationSelector]) {
236 [self swizzleSelector:willPresentNotificationSelector
237 inClass:[delegate class]
238 withImplementation:(IMP)FCM_swizzle_willPresentNotificationWithHandler
239 inProtocol:userNotificationCenterProtocol];
241 SEL didReceiveNotificationResponseSelector =
242 NSSelectorFromString(kUserNotificationDidReceiveResponseSelectorString);
243 if ([delegate respondsToSelector:didReceiveNotificationResponseSelector]) {
244 [self swizzleSelector:didReceiveNotificationResponseSelector
245 inClass:[delegate class]
246 withImplementation:(IMP)FCM_swizzle_didReceiveNotificationResponseWithHandler
247 inProtocol:userNotificationCenterProtocol];
249 self.currentUserNotificationCenterDelegate = delegate;
250 self.hasSwizzledUserNotificationDelegate = YES;
254 - (void)unswizzleUserNotificationCenterDelegate:(id _Nonnull)delegate {
255 if (self.currentUserNotificationCenterDelegate != delegate) {
256 // We aren't swizzling this delegate, so don't do anything.
259 SEL willPresentNotificationSelector =
260 NSSelectorFromString(kUserNotificationWillPresentSelectorString);
261 // Call unswizzle methods, even if the method was not implemented (it will fail gracefully).
262 [self unswizzleSelector:willPresentNotificationSelector
263 inClass:[self.currentUserNotificationCenterDelegate class]];
264 SEL didReceiveNotificationResponseSelector =
265 NSSelectorFromString(kUserNotificationDidReceiveResponseSelectorString);
266 [self unswizzleSelector:didReceiveNotificationResponseSelector
267 inClass:[self.currentUserNotificationCenterDelegate class]];
268 self.currentUserNotificationCenterDelegate = nil;
269 self.hasSwizzledUserNotificationDelegate = NO;
272 #pragma mark - KVO for UNUserNotificationCenter
274 - (void)addDelegateObserverToUserNotificationCenter:(id)userNotificationCenter {
275 [self removeUserNotificationCenterDelegateObserver];
277 [userNotificationCenter addObserver:self
278 forKeyPath:NSStringFromSelector(@selector(delegate))
279 options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
280 context:UserNotificationObserverContext];
281 self.userNotificationCenter = userNotificationCenter;
282 self.isObservingUserNotificationDelegateChanges = YES;
283 } @catch (NSException *exception) {
284 FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy000,
285 @"Encountered exception trying to add a KVO observer for "
286 @"UNUserNotificationCenter's 'delegate' property: %@",
293 - (void)removeUserNotificationCenterDelegateObserver {
294 if (!self.userNotificationCenter) {
298 [self.userNotificationCenter removeObserver:self
299 forKeyPath:NSStringFromSelector(@selector(delegate))
300 context:UserNotificationObserverContext];
301 self.userNotificationCenter = nil;
302 self.isObservingUserNotificationDelegateChanges = NO;
303 } @catch (NSException *exception) {
304 FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy001,
305 @"Encountered exception trying to remove a KVO observer for "
306 @"UNUserNotificationCenter's 'delegate' property: %@",
313 - (void)observeValueForKeyPath:(NSString *)keyPath
315 change:(NSDictionary<NSKeyValueChangeKey, id> *)change
316 context:(void *)context {
317 if (context == UserNotificationObserverContext) {
318 if ([keyPath isEqualToString:NSStringFromSelector(@selector(delegate))]) {
319 id oldDelegate = change[NSKeyValueChangeOldKey];
320 if (oldDelegate && oldDelegate != [NSNull null]) {
321 [self unswizzleUserNotificationCenterDelegate:oldDelegate];
323 id newDelegate = change[NSKeyValueChangeNewKey];
324 if (newDelegate && newDelegate != [NSNull null]) {
325 [self swizzleUserNotificationCenterDelegate:newDelegate];
329 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
333 #pragma mark - NSProxy methods
335 - (void)saveOriginalImplementation:(IMP)imp forSelector:(SEL)selector {
336 if (imp && selector) {
337 NSValue *IMPValue = [NSValue valueWithPointer:imp];
338 NSString *selectorString = NSStringFromSelector(selector);
339 self.originalAppDelegateImps[selectorString] = IMPValue;
343 - (IMP)originalImplementationForSelector:(SEL)selector {
344 NSString *selectorString = NSStringFromSelector(selector);
345 NSValue *implementation_value = self.originalAppDelegateImps[selectorString];
346 if (!implementation_value) {
351 [implementation_value getValue:&imp];
355 - (void)trackSwizzledSelector:(SEL)selector ofClass:(Class)klass {
356 NSString *className = NSStringFromClass(klass);
357 NSString *selectorString = NSStringFromSelector(selector);
358 NSArray *selectors = self.swizzledSelectorsByClass[selectorString];
360 selectors = [selectors arrayByAddingObject:selectorString];
362 selectors = @[selectorString];
364 self.swizzledSelectorsByClass[className] = selectors;
367 - (void)removeImplementationForSelector:(SEL)selector {
368 NSString *selectorString = NSStringFromSelector(selector);
369 [self.originalAppDelegateImps removeObjectForKey:selectorString];
372 - (void)swizzleSelector:(SEL)originalSelector
374 withImplementation:(IMP)swizzledImplementation
375 inProtocol:(Protocol *)protocol {
376 Method originalMethod = class_getInstanceMethod(klass, originalSelector);
378 if (originalMethod) {
379 // This class implements this method, so replace the original implementation
380 // with our new implementation and save the old implementation.
382 IMP __original_method_implementation =
383 method_setImplementation(originalMethod, swizzledImplementation);
385 IMP __nonexistant_method_implementation = [self nonExistantMethodImplementationForClass:klass];
387 if (__original_method_implementation &&
388 __original_method_implementation != __nonexistant_method_implementation &&
389 __original_method_implementation != swizzledImplementation) {
390 [self saveOriginalImplementation:__original_method_implementation
391 forSelector:originalSelector];
394 // The class doesn't have this method, so add our swizzled implementation as the
395 // original implementation of the original method.
396 struct objc_method_description method_description =
397 protocol_getMethodDescription(protocol, originalSelector, NO, YES);
399 BOOL methodAdded = class_addMethod(klass,
401 swizzledImplementation,
402 method_description.types);
404 FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyMethodNotAdded,
405 @"Could not add method for %@ to class %@",
406 NSStringFromSelector(originalSelector),
407 NSStringFromClass(klass));
410 [self trackSwizzledSelector:originalSelector ofClass:klass];
413 - (void)unswizzleSelector:(SEL)selector inClass:(Class)klass {
415 Method swizzledMethod = class_getInstanceMethod(klass, selector);
416 if (!swizzledMethod) {
417 // This class doesn't seem to have this selector as an instance method? Bail out.
421 IMP original_imp = [self originalImplementationForSelector:selector];
423 // Restore the original implementation as the current implementation
424 method_setImplementation(swizzledMethod, original_imp);
425 [self removeImplementationForSelector:selector];
427 // This class originally did not have an implementation for this selector.
429 // We can't actually remove methods in Objective C 2.0, but we could set
430 // its method to something non-existent. This should give us the same
431 // behavior as if the method was not implemented.
432 // See: http://stackoverflow.com/a/8276527/9849
434 IMP nonExistantMethodImplementation = [self nonExistantMethodImplementationForClass:klass];
435 method_setImplementation(swizzledMethod, nonExistantMethodImplementation);
439 #pragma mark - Reflection Helpers
441 // This is useful to generate from a stable, "known missing" selector, as the IMP can be compared
442 // in case we are setting an implementation for a class that was previously "unswizzled" into a
443 // non-existant implementation.
444 - (IMP)nonExistantMethodImplementationForClass:(Class)klass {
445 SEL nonExistantSelector = NSSelectorFromString(@"aNonExistantMethod");
446 IMP nonExistantMethodImplementation = class_getMethodImplementation(klass, nonExistantSelector);
447 return nonExistantMethodImplementation;
450 // A safe, non-leaky way return a property object by its name
451 id getNamedPropertyFromObject(id object, NSString *propertyName, Class klass) {
452 SEL selector = NSSelectorFromString(propertyName);
453 if (![object respondsToSelector:selector]) {
457 klass = [NSObject class];
459 // Suppress clang warning about leaks in performSelector
460 // The alternative way to perform this is to invoke
461 // the method as a block (see http://stackoverflow.com/a/20058585),
462 // but this approach sometimes returns incomplete objects.
463 #pragma clang diagnostic push
464 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
465 id property = [object performSelector:selector];
466 #pragma clang diagnostic pop
467 if (![property isKindOfClass:klass]) {
473 #pragma mark - Swizzled Methods
475 void FCM_swizzle_appDidReceiveRemoteNotification(id self,
478 NSDictionary *userInfo) {
479 [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
482 [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
484 ((void (*)(id, SEL, UIApplication *, NSDictionary *))original_imp)(self,
491 void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler(
492 id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
493 void (^handler)(UIBackgroundFetchResult)) {
495 [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
498 [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
500 ((void (*)(id, SEL, UIApplication *, NSDictionary *,
501 void (^)(UIBackgroundFetchResult)))original_imp)(
502 self, _cmd, app, userInfo, handler);
507 * Swizzle the notification handler for iOS 10+ devices.
508 * Signature of original handler is as below:
509 * - (void)userNotificationCenter:(UNUserNotificationCenter *)center
510 * willPresentNotification:(UNNotification *)notification
511 * withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
512 * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
513 * parameter types from the swizzling implementation.
515 void FCM_swizzle_willPresentNotificationWithHandler(
516 id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger)) {
518 FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
519 IMP original_imp = [proxy originalImplementationForSelector:_cmd];
521 void (^callOriginalMethodIfAvailable)(void) = ^{
523 ((void (*)(id, SEL, id, id, void (^)(NSUInteger)))original_imp)(
524 self, _cmd, center, notification, handler);
529 Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
530 Class notificationClass = NSClassFromString(@"UNNotification");
531 if (!notificationCenterClass || !notificationClass) {
532 // Can't find UserNotifications framework. Do not swizzle, just execute the original method.
533 callOriginalMethodIfAvailable();
536 if (!center || ![center isKindOfClass:[notificationCenterClass class]]) {
537 // Invalid parameter type from the original method.
538 // Do not swizzle, just execute the original method.
539 callOriginalMethodIfAvailable();
543 if (!notification || ![notification isKindOfClass:[notificationClass class]]) {
544 // Invalid parameter type from the original method.
545 // Do not swizzle, just execute the original method.
546 callOriginalMethodIfAvailable();
551 // Invalid parameter type from the original method.
552 // Do not swizzle, just execute the original method.
553 callOriginalMethodIfAvailable();
557 // Attempt to access the user info
558 id notificationUserInfo = userInfoFromNotification(notification);
560 if (!notificationUserInfo) {
561 // Could not access notification.request.content.userInfo.
562 callOriginalMethodIfAvailable();
566 [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
567 // Execute the original implementation.
568 callOriginalMethodIfAvailable();
572 * Swizzle the notification handler for iOS 10+ devices.
573 * Signature of original handler is as below:
574 * - (void)userNotificationCenter:(UNUserNotificationCenter *)center
575 * didReceiveNotificationResponse:(UNNotificationResponse *)response
576 * withCompletionHandler:(void (^)(void))completionHandler
577 * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
578 * parameter types from the swizzling implementation.
580 void FCM_swizzle_didReceiveNotificationResponseWithHandler(
581 id self, SEL _cmd, id center, id response, void (^handler)(void)) {
583 FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
584 IMP original_imp = [proxy originalImplementationForSelector:_cmd];
586 void (^callOriginalMethodIfAvailable)(void) = ^{
588 ((void (*)(id, SEL, id, id, void (^)(void)))original_imp)(
589 self, _cmd, center, response, handler);
594 Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
595 Class responseClass = NSClassFromString(@"UNNotificationResponse");
596 if (!center || ![center isKindOfClass:[notificationCenterClass class]]) {
597 // Invalid parameter type from the original method.
598 // Do not swizzle, just execute the original method.
599 callOriginalMethodIfAvailable();
603 if (!response || ![response isKindOfClass:[responseClass class]]) {
604 // Invalid parameter type from the original method.
605 // Do not swizzle, just execute the original method.
606 callOriginalMethodIfAvailable();
611 // Invalid parameter type from the original method.
612 // Do not swizzle, just execute the original method.
613 callOriginalMethodIfAvailable();
617 // Try to access the response.notification property
618 SEL notificationSelector = NSSelectorFromString(@"notification");
619 if (![response respondsToSelector:notificationSelector]) {
620 // Cannot access the .notification property.
621 callOriginalMethodIfAvailable();
624 id notificationClass = NSClassFromString(@"UNNotification");
625 id notification = getNamedPropertyFromObject(response, @"notification", notificationClass);
627 // With a notification object, use the common code to reach deep into notification
628 // (notification.request.content.userInfo)
629 id notificationUserInfo = userInfoFromNotification(notification);
630 if (!notificationUserInfo) {
631 // Could not access notification.request.content.userInfo.
632 callOriginalMethodIfAvailable();
636 [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
637 // Execute the original implementation.
638 callOriginalMethodIfAvailable();
641 id userInfoFromNotification(id notification) {
643 // Select the userInfo field from UNNotification.request.content.userInfo.
644 SEL requestSelector = NSSelectorFromString(@"request");
645 if (![notification respondsToSelector:requestSelector]) {
646 // Cannot access the request property.
649 Class requestClass = NSClassFromString(@"UNNotificationRequest");
650 id notificationRequest = getNamedPropertyFromObject(notification, @"request", requestClass);
652 SEL notificationContentSelector = NSSelectorFromString(@"content");
653 if (!notificationRequest
654 || ![notificationRequest respondsToSelector:notificationContentSelector]) {
655 // Cannot access the content property.
658 Class contentClass = NSClassFromString(@"UNNotificationContent");
659 id notificationContent = getNamedPropertyFromObject(notificationRequest,
663 SEL notificationUserInfoSelector = NSSelectorFromString(@"userInfo");
664 if (!notificationContent
665 || ![notificationContent respondsToSelector:notificationUserInfoSelector]) {
666 // Cannot access the userInfo property.
669 id notificationUserInfo = getNamedPropertyFromObject(notificationContent,
671 [NSDictionary class]);
673 if (!notificationUserInfo) {
674 // This is not the expected notification handler.
678 return notificationUserInfo;
681 void FCM_swizzle_messagingDidReceiveMessage(id self, SEL _cmd, FIRMessaging *message,
682 FIRMessagingRemoteMessage *remoteMessage) {
683 [[FIRMessaging messaging] appDidReceiveMessage:remoteMessage.appData];
686 [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
688 ((void (*)(id, SEL, FIRMessaging *, FIRMessagingRemoteMessage *))original_imp)(
689 self, _cmd, message, remoteMessage);
693 void FCM_swizzle_appDidFailToRegisterForRemoteNotifications(id self,
697 // Log the fact that we failed to register for remote notifications
698 FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed,
700 @"application:didFailToRegisterForRemoteNotificationsWithError: %@",
701 error.localizedDescription);
703 [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
705 ((void (*)(id, SEL, UIApplication *, NSError *))original_imp)(self, _cmd, app, error);
709 void FCM_swizzle_appDidRegisterForRemoteNotifications(id self,
712 NSData *deviceToken) {
713 // Pass the APNSToken along to FIRMessaging (and auto-detect the token type)
714 [FIRMessaging messaging].APNSToken = deviceToken;
717 [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
719 ((void (*)(id, SEL, UIApplication *, NSData *))original_imp)(self, _cmd, app, deviceToken);