You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

714 lines
28 KiB

/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FIRMessagingRemoteNotificationsProxy.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import "FIRMessagingConstants.h"
#import "FIRMessagingLogger.h"
#import "FIRMessaging_Private.h"
static const BOOL kDefaultAutoRegisterEnabledValue = YES;
static void * UserNotificationObserverContext = &UserNotificationObserverContext;
static NSString *kUserNotificationWillPresentSelectorString =
@"userNotificationCenter:willPresentNotification:withCompletionHandler:";
static NSString *kUserNotificationDidReceiveResponseSelectorString =
@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:";
static NSString *kReceiveDataMessageSelectorString = @"messaging:didReceiveMessage:";
@interface FIRMessagingRemoteNotificationsProxy ()
@property(strong, nonatomic) NSMutableDictionary<NSString *, NSValue *> *originalAppDelegateImps;
@property(strong, nonatomic) NSMutableDictionary<NSString *, NSArray *> *swizzledSelectorsByClass;
@property(nonatomic) BOOL didSwizzleMethods;
@property(nonatomic) BOOL didSwizzleAppDelegateMethods;
@property(nonatomic) BOOL hasSwizzledUserNotificationDelegate;
@property(nonatomic) BOOL isObservingUserNotificationDelegateChanges;
@property(strong, nonatomic) id userNotificationCenter;
@property(strong, nonatomic) id currentUserNotificationCenterDelegate;
@end
@implementation FIRMessagingRemoteNotificationsProxy
+ (BOOL)canSwizzleMethods {
id canSwizzleValue =
[[NSBundle mainBundle]
objectForInfoDictionaryKey: kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey];
if (canSwizzleValue && [canSwizzleValue isKindOfClass:[NSNumber class]]) {
NSNumber *canSwizzleNumberValue = (NSNumber *)canSwizzleValue;
return canSwizzleNumberValue.boolValue;
} else {
return kDefaultAutoRegisterEnabledValue;
}
}
+ (void)swizzleMethods {
[[FIRMessagingRemoteNotificationsProxy sharedProxy] swizzleMethodsIfPossible];
}
+ (instancetype)sharedProxy {
static FIRMessagingRemoteNotificationsProxy *proxy;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
});
return proxy;
}
- (instancetype)init {
self = [super init];
if (self) {
_originalAppDelegateImps = [[NSMutableDictionary alloc] init];
_swizzledSelectorsByClass = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc {
[self unswizzleAllMethods];
self.swizzledSelectorsByClass = nil;
[self.originalAppDelegateImps removeAllObjects];
self.originalAppDelegateImps = nil;
[self removeUserNotificationCenterDelegateObserver];
}
- (void)swizzleMethodsIfPossible {
// Already swizzled.
if (self.didSwizzleMethods) {
return;
}
NSObject<UIApplicationDelegate> *appDelegate = [[UIApplication sharedApplication] delegate];
[self swizzleAppDelegateMethods:appDelegate];
// Add KVO listener on [UNUserNotificationCenter currentNotificationCenter]'s delegate property
Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
if (notificationCenterClass) {
// We are linked against iOS 10 SDK or above
id notificationCenter = getNamedPropertyFromObject(notificationCenterClass,
@"currentNotificationCenter",
notificationCenterClass);
if (notificationCenter) {
[self listenForDelegateChangesInUserNotificationCenter:notificationCenter];
}
}
self.didSwizzleMethods = YES;
}
- (void)unswizzleAllMethods {
for (NSString *className in self.swizzledSelectorsByClass) {
Class klass = NSClassFromString(className);
NSArray *selectorStrings = self.swizzledSelectorsByClass[className];
for (NSString *selectorString in selectorStrings) {
SEL selector = NSSelectorFromString(selectorString);
[self unswizzleSelector:selector inClass:klass];
}
}
[self.swizzledSelectorsByClass removeAllObjects];
}
- (void)swizzleAppDelegateMethods:(id<UIApplicationDelegate>)appDelegate {
if (![appDelegate conformsToProtocol:@protocol(UIApplicationDelegate)]) {
return;
}
Class appDelegateClass = [appDelegate class];
BOOL didSwizzleAppDelegate = NO;
// Message receiving handler for iOS 9, 8, 7 devices (both display notification and data message).
SEL remoteNotificationSelector =
@selector(application:didReceiveRemoteNotification:);
SEL remoteNotificationWithFetchHandlerSelector =
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
// For recording when APNS tokens are registered (or fail to register)
SEL registerForAPNSFailSelector =
@selector(application:didFailToRegisterForRemoteNotificationsWithError:);
SEL registerForAPNSSuccessSelector =
@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);
// Receive Remote Notifications.
BOOL selectorWithFetchHandlerImplemented = NO;
if ([appDelegate respondsToSelector:remoteNotificationWithFetchHandlerSelector]) {
selectorWithFetchHandlerImplemented = YES;
[self swizzleSelector:remoteNotificationWithFetchHandlerSelector
inClass:appDelegateClass
withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotificationWithHandler
inProtocol:@protocol(UIApplicationDelegate)];
didSwizzleAppDelegate = YES;
}
if ([appDelegate respondsToSelector:remoteNotificationSelector] ||
!selectorWithFetchHandlerImplemented) {
[self swizzleSelector:remoteNotificationSelector
inClass:appDelegateClass
withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotification
inProtocol:@protocol(UIApplicationDelegate)];
didSwizzleAppDelegate = YES;
}
// For data message from MCS.
SEL receiveDataMessageSelector = NSSelectorFromString(kReceiveDataMessageSelectorString);
if ([appDelegate respondsToSelector:receiveDataMessageSelector]) {
[self swizzleSelector:receiveDataMessageSelector
inClass:appDelegateClass
withImplementation:(IMP)FCM_swizzle_messagingDidReceiveMessage
inProtocol:@protocol(UIApplicationDelegate)];
didSwizzleAppDelegate = YES;
}
// Receive APNS token
[self swizzleSelector:registerForAPNSSuccessSelector
inClass:appDelegateClass
withImplementation:(IMP)FCM_swizzle_appDidRegisterForRemoteNotifications
inProtocol:@protocol(UIApplicationDelegate)];
[self swizzleSelector:registerForAPNSFailSelector
inClass:appDelegateClass
withImplementation:(IMP)FCM_swizzle_appDidFailToRegisterForRemoteNotifications
inProtocol:@protocol(UIApplicationDelegate)];
self.didSwizzleAppDelegateMethods = didSwizzleAppDelegate;
}
- (void)listenForDelegateChangesInUserNotificationCenter:(id)notificationCenter {
Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
if (![notificationCenter isKindOfClass:notificationCenterClass]) {
return;
}
id delegate = getNamedPropertyFromObject(notificationCenter, @"delegate", nil);
Protocol *delegateProtocol = NSProtocolFromString(@"UNUserNotificationCenterDelegate");
if ([delegate conformsToProtocol:delegateProtocol]) {
// Swizzle this object now, if available
[self swizzleUserNotificationCenterDelegate:delegate];
}
// Add KVO observer for "delegate" keyPath for future changes
[self addDelegateObserverToUserNotificationCenter:notificationCenter];
}
#pragma mark - UNNotificationCenter Swizzling
- (void)swizzleUserNotificationCenterDelegate:(id)delegate {
if (self.currentUserNotificationCenterDelegate == delegate) {
// Via pointer-check, compare if we have already swizzled this item.
return;
}
Protocol *userNotificationCenterProtocol =
NSProtocolFromString(@"UNUserNotificationCenterDelegate");
if ([delegate conformsToProtocol:userNotificationCenterProtocol]) {
SEL willPresentNotificationSelector =
NSSelectorFromString(kUserNotificationWillPresentSelectorString);
// Swizzle the optional method
// "userNotificationCenter:willPresentNotification:withCompletionHandler:", if it is
// implemented. Do not swizzle otherwise, as an implementation *will* be created, which will
// fool iOS into thinking that this method is implemented, and therefore not send notifications
// to the fallback method in the app delegate
// "application:didReceiveRemoteNotification:fetchCompletionHandler:".
if ([delegate respondsToSelector:willPresentNotificationSelector]) {
[self swizzleSelector:willPresentNotificationSelector
inClass:[delegate class]
withImplementation:(IMP)FCM_swizzle_willPresentNotificationWithHandler
inProtocol:userNotificationCenterProtocol];
}
SEL didReceiveNotificationResponseSelector =
NSSelectorFromString(kUserNotificationDidReceiveResponseSelectorString);
if ([delegate respondsToSelector:didReceiveNotificationResponseSelector]) {
[self swizzleSelector:didReceiveNotificationResponseSelector
inClass:[delegate class]
withImplementation:(IMP)FCM_swizzle_didReceiveNotificationResponseWithHandler
inProtocol:userNotificationCenterProtocol];
}
self.currentUserNotificationCenterDelegate = delegate;
self.hasSwizzledUserNotificationDelegate = YES;
}
}
- (void)unswizzleUserNotificationCenterDelegate:(id)delegate {
if (self.currentUserNotificationCenterDelegate != delegate) {
// We aren't swizzling this delegate, so don't do anything.
return;
}
SEL willPresentNotificationSelector =
NSSelectorFromString(kUserNotificationWillPresentSelectorString);
// Call unswizzle methods, even if the method was not implemented (it will fail gracefully).
[self unswizzleSelector:willPresentNotificationSelector
inClass:[self.currentUserNotificationCenterDelegate class]];
self.currentUserNotificationCenterDelegate = nil;
self.hasSwizzledUserNotificationDelegate = NO;
}
#pragma mark - KVO for UNUserNotificationCenter
- (void)addDelegateObserverToUserNotificationCenter:(id)userNotificationCenter {
[self removeUserNotificationCenterDelegateObserver];
@try {
[userNotificationCenter addObserver:self
forKeyPath:NSStringFromSelector(@selector(delegate))
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:UserNotificationObserverContext];
self.userNotificationCenter = userNotificationCenter;
self.isObservingUserNotificationDelegateChanges = YES;
} @catch (NSException *exception) {
FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy000,
@"Encountered exception trying to add a KVO observer for "
@"UNUserNotificationCenter's 'delegate' property: %@",
exception);
} @finally {
}
}
- (void)removeUserNotificationCenterDelegateObserver {
if (!self.userNotificationCenter) {
return;
}
@try {
[self.userNotificationCenter removeObserver:self
forKeyPath:NSStringFromSelector(@selector(delegate))
context:UserNotificationObserverContext];
self.userNotificationCenter = nil;
self.isObservingUserNotificationDelegateChanges = NO;
} @catch (NSException *exception) {
FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy001,
@"Encountered exception trying to remove a KVO observer for "
@"UNUserNotificationCenter's 'delegate' property: %@",
exception);
} @finally {
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context {
if (context == UserNotificationObserverContext) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(delegate))]) {
id oldDelegate = change[NSKeyValueChangeOldKey];
if (oldDelegate && oldDelegate != [NSNull null]) {
[self unswizzleUserNotificationCenterDelegate:oldDelegate];
}
id newDelegate = change[NSKeyValueChangeNewKey];
if (newDelegate && newDelegate != [NSNull null]) {
[self swizzleUserNotificationCenterDelegate:newDelegate];
}
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - NSProxy methods
- (void)saveOriginalImplementation:(IMP)imp forSelector:(SEL)selector {
if (imp && selector) {
NSValue *IMPValue = [NSValue valueWithPointer:imp];
NSString *selectorString = NSStringFromSelector(selector);
self.originalAppDelegateImps[selectorString] = IMPValue;
}
}
- (IMP)originalImplementationForSelector:(SEL)selector {
NSString *selectorString = NSStringFromSelector(selector);
NSValue *implementation_value = self.originalAppDelegateImps[selectorString];
if (!implementation_value) {
return nil;
}
IMP imp;
[implementation_value getValue:&imp];
return imp;
}
- (void)trackSwizzledSelector:(SEL)selector ofClass:(Class)klass {
NSString *className = NSStringFromClass(klass);
NSString *selectorString = NSStringFromSelector(selector);
NSArray *selectors = self.swizzledSelectorsByClass[selectorString];
if (selectors) {
selectors = [selectors arrayByAddingObject:selectorString];
} else {
selectors = @[selectorString];
}
self.swizzledSelectorsByClass[className] = selectors;
}
- (void)removeImplementationForSelector:(SEL)selector {
NSString *selectorString = NSStringFromSelector(selector);
[self.originalAppDelegateImps removeObjectForKey:selectorString];
}
- (void)swizzleSelector:(SEL)originalSelector
inClass:(Class)klass
withImplementation:(IMP)swizzledImplementation
inProtocol:(Protocol *)protocol {
Method originalMethod = class_getInstanceMethod(klass, originalSelector);
if (originalMethod) {
// This class implements this method, so replace the original implementation
// with our new implementation and save the old implementation.
IMP __original_method_implementation =
method_setImplementation(originalMethod, swizzledImplementation);
IMP __nonexistant_method_implementation = [self nonExistantMethodImplementationForClass:klass];
if (__original_method_implementation &&
__original_method_implementation != __nonexistant_method_implementation &&
__original_method_implementation != swizzledImplementation) {
[self saveOriginalImplementation:__original_method_implementation
forSelector:originalSelector];
}
} else {
// The class doesn't have this method, so add our swizzled implementation as the
// original implementation of the original method.
struct objc_method_description method_description =
protocol_getMethodDescription(protocol, originalSelector, NO, YES);
BOOL methodAdded = class_addMethod(klass,
originalSelector,
swizzledImplementation,
method_description.types);
if (!methodAdded) {
FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyMethodNotAdded,
@"Could not add method for %@ to class %@",
NSStringFromSelector(originalSelector),
NSStringFromClass(klass));
}
}
[self trackSwizzledSelector:originalSelector ofClass:klass];
}
- (void)unswizzleSelector:(SEL)selector inClass:(Class)klass {
Method swizzledMethod = class_getInstanceMethod(klass, selector);
if (!swizzledMethod) {
// This class doesn't seem to have this selector as an instance method? Bail out.
return;
}
IMP original_imp = [self originalImplementationForSelector:selector];
if (original_imp) {
// Restore the original implementation as the current implementation
method_setImplementation(swizzledMethod, original_imp);
[self removeImplementationForSelector:selector];
} else {
// This class originally did not have an implementation for this selector.
// We can't actually remove methods in Objective C 2.0, but we could set
// its method to something non-existent. This should give us the same
// behavior as if the method was not implemented.
// See: http://stackoverflow.com/a/8276527/9849
IMP nonExistantMethodImplementation = [self nonExistantMethodImplementationForClass:klass];
method_setImplementation(swizzledMethod, nonExistantMethodImplementation);
}
}
#pragma mark - Reflection Helpers
// This is useful to generate from a stable, "known missing" selector, as the IMP can be compared
// in case we are setting an implementation for a class that was previously "unswizzled" into a
// non-existant implementation.
- (IMP)nonExistantMethodImplementationForClass:(Class)klass {
SEL nonExistantSelector = NSSelectorFromString(@"aNonExistantMethod");
IMP nonExistantMethodImplementation = class_getMethodImplementation(klass, nonExistantSelector);
return nonExistantMethodImplementation;
}
// A safe, non-leaky way return a property object by its name
id getNamedPropertyFromObject(id object, NSString *propertyName, Class klass) {
SEL selector = NSSelectorFromString(propertyName);
if (![object respondsToSelector:selector]) {
return nil;
}
if (!klass) {
klass = [NSObject class];
}
// Suppress clang warning about leaks in performSelector
// The alternative way to perform this is to invoke
// the method as a block (see http://stackoverflow.com/a/20058585),
// but this approach sometimes returns incomplete objects.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id property = [object performSelector:selector];
#pragma clang diagnostic pop
if (![property isKindOfClass:klass]) {
return nil;
}
return property;
}
#pragma mark - Swizzled Methods
void FCM_swizzle_appDidReceiveRemoteNotification(id self,
SEL _cmd,
UIApplication *app,
NSDictionary *userInfo) {
[[FIRMessaging messaging] appDidReceiveMessage:userInfo];
IMP original_imp =
[[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
if (original_imp) {
((void (*)(id, SEL, UIApplication *, NSDictionary *))original_imp)(self,
_cmd,
app,
userInfo);
}
}
void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler(
id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
void (^handler)(UIBackgroundFetchResult)) {
[[FIRMessaging messaging] appDidReceiveMessage:userInfo];
IMP original_imp =
[[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
if (original_imp) {
((void (*)(id, SEL, UIApplication *, NSDictionary *,
void (^)(UIBackgroundFetchResult)))original_imp)(
self, _cmd, app, userInfo, handler);
}
}
/**
* Swizzle the notification handler for iOS 10+ devices.
* Signature of original handler is as below:
* - (void)userNotificationCenter:(UNUserNotificationCenter *)center
* willPresentNotification:(UNNotification *)notification
* withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
* In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
* parameter types from the swizzling implementation.
*/
void FCM_swizzle_willPresentNotificationWithHandler(
id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger)) {
FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
IMP original_imp = [proxy originalImplementationForSelector:_cmd];
void (^callOriginalMethodIfAvailable)(void) = ^{
if (original_imp) {
((void (*)(id, SEL, id, id, void (^)(NSUInteger)))original_imp)(
self, _cmd, center, notification, handler);
}
return;
};
Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
Class notificationClass = NSClassFromString(@"UNNotification");
if (!notificationCenterClass || !notificationClass) {
// Can't find UserNotifications framework. Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
}
if (!center || ![center isKindOfClass:[notificationCenterClass class]]) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
if (!notification || ![notification isKindOfClass:[notificationClass class]]) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
if (!handler) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
// Attempt to access the user info
id notificationUserInfo = userInfoFromNotification(notification);
if (!notificationUserInfo) {
// Could not access notification.request.content.userInfo.
callOriginalMethodIfAvailable();
return;
}
[[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
// Execute the original implementation.
callOriginalMethodIfAvailable();
}
/**
* Swizzle the notification handler for iOS 10+ devices.
* Signature of original handler is as below:
* - (void)userNotificationCenter:(UNUserNotificationCenter *)center
* didReceiveNotificationResponse:(UNNotificationResponse *)response
* withCompletionHandler:(void (^)(void))completionHandler
* In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
* parameter types from the swizzling implementation.
*/
void FCM_swizzle_didReceiveNotificationResponseWithHandler(
id self, SEL _cmd, id center, id response, void (^handler)(void)) {
FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
IMP original_imp = [proxy originalImplementationForSelector:_cmd];
void (^callOriginalMethodIfAvailable)(void) = ^{
if (original_imp) {
((void (*)(id, SEL, id, id, void (^)(void)))original_imp)(
self, _cmd, center, response, handler);
}
return;
};
Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
Class responseClass = NSClassFromString(@"UNNotificationResponse");
if (!center || ![center isKindOfClass:[notificationCenterClass class]]) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
if (!response || ![response isKindOfClass:[responseClass class]]) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
if (!handler) {
// Invalid parameter type from the original method.
// Do not swizzle, just execute the original method.
callOriginalMethodIfAvailable();
return;
}
// Try to access the response.notification property
SEL notificationSelector = NSSelectorFromString(@"notification");
if (![response respondsToSelector:notificationSelector]) {
// Cannot access the .notification property.
callOriginalMethodIfAvailable();
return;
}
id notificationClass = NSClassFromString(@"UNNotification");
id notification = getNamedPropertyFromObject(response, @"notification", notificationClass);
// With a notification object, use the common code to reach deep into notification
// (notification.request.content.userInfo)
id notificationUserInfo = userInfoFromNotification(notification);
if (!notificationUserInfo) {
// Could not access notification.request.content.userInfo.
callOriginalMethodIfAvailable();
return;
}
[[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
// Execute the original implementation.
callOriginalMethodIfAvailable();
}
id userInfoFromNotification(id notification) {
// Select the userInfo field from UNNotification.request.content.userInfo.
SEL requestSelector = NSSelectorFromString(@"request");
if (![notification respondsToSelector:requestSelector]) {
// Cannot access the request property.
return nil;
}
Class requestClass = NSClassFromString(@"UNNotificationRequest");
id notificationRequest = getNamedPropertyFromObject(notification, @"request", requestClass);
SEL notificationContentSelector = NSSelectorFromString(@"content");
if (!notificationRequest
|| ![notificationRequest respondsToSelector:notificationContentSelector]) {
// Cannot access the content property.
return nil;
}
Class contentClass = NSClassFromString(@"UNNotificationContent");
id notificationContent = getNamedPropertyFromObject(notificationRequest,
@"content",
contentClass);
SEL notificationUserInfoSelector = NSSelectorFromString(@"userInfo");
if (!notificationContent
|| ![notificationContent respondsToSelector:notificationUserInfoSelector]) {
// Cannot access the userInfo property.
return nil;
}
id notificationUserInfo = getNamedPropertyFromObject(notificationContent,
@"userInfo",
[NSDictionary class]);
if (!notificationUserInfo) {
// This is not the expected notification handler.
return nil;
}
return notificationUserInfo;
}
void FCM_swizzle_messagingDidReceiveMessage(id self, SEL _cmd, FIRMessaging *message,
FIRMessagingRemoteMessage *remoteMessage) {
[[FIRMessaging messaging] appDidReceiveMessage:remoteMessage.appData];
IMP original_imp =
[[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
if (original_imp) {
((void (*)(id, SEL, FIRMessaging *, FIRMessagingRemoteMessage *))original_imp)(
self, _cmd, message, remoteMessage);
}
}
void FCM_swizzle_appDidFailToRegisterForRemoteNotifications(id self,
SEL _cmd,
UIApplication *app,
NSError *error) {
// Log the fact that we failed to register for remote notifications
FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed,
@"Error in "
@"application:didFailToRegisterForRemoteNotificationsWithError: %@",
error.localizedDescription);
IMP original_imp =
[[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
if (original_imp) {
((void (*)(id, SEL, UIApplication *, NSError *))original_imp)(self, _cmd, app, error);
}
}
void FCM_swizzle_appDidRegisterForRemoteNotifications(id self,
SEL _cmd,
UIApplication *app,
NSData *deviceToken) {
// Pass the APNSToken along to FIRMessaging (and auto-detect the token type)
[FIRMessaging messaging].APNSToken = deviceToken;
IMP original_imp =
[[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
if (original_imp) {
((void (*)(id, SEL, UIApplication *, NSData *))original_imp)(self, _cmd, app, deviceToken);
}
}
@end