FIRMessagingRemoteNotificationsProxy.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*
  2. * Copyright 2017 Google
  3. *
  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
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  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.
  15. */
  16. #import "FIRMessagingRemoteNotificationsProxy.h"
  17. #import <objc/runtime.h>
  18. #import <UIKit/UIKit.h>
  19. #import "FIRMessagingConstants.h"
  20. #import "FIRMessagingLogger.h"
  21. #import "FIRMessaging_Private.h"
  22. static const BOOL kDefaultAutoRegisterEnabledValue = YES;
  23. static void * UserNotificationObserverContext = &UserNotificationObserverContext;
  24. static NSString *kUserNotificationWillPresentSelectorString =
  25. @"userNotificationCenter:willPresentNotification:withCompletionHandler:";
  26. @interface FIRMessagingRemoteNotificationsProxy ()
  27. @property(strong, nonatomic) NSMutableDictionary<NSString *, NSValue *> *originalAppDelegateImps;
  28. @property(strong, nonatomic) NSMutableDictionary<NSString *, NSArray *> *swizzledSelectorsByClass;
  29. @property(nonatomic) BOOL didSwizzleMethods;
  30. @property(nonatomic) BOOL didSwizzleAppDelegateMethods;
  31. @property(nonatomic) BOOL hasSwizzledUserNotificationDelegate;
  32. @property(nonatomic) BOOL isObservingUserNotificationDelegateChanges;
  33. @property(strong, nonatomic) id userNotificationCenter;
  34. @property(strong, nonatomic) id currentUserNotificationCenterDelegate;
  35. @end
  36. @implementation FIRMessagingRemoteNotificationsProxy
  37. + (BOOL)canSwizzleMethods {
  38. id canSwizzleValue =
  39. [[NSBundle mainBundle]
  40. objectForInfoDictionaryKey: kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey];
  41. if (canSwizzleValue && [canSwizzleValue isKindOfClass:[NSNumber class]]) {
  42. NSNumber *canSwizzleNumberValue = (NSNumber *)canSwizzleValue;
  43. return canSwizzleNumberValue.boolValue;
  44. } else {
  45. return kDefaultAutoRegisterEnabledValue;
  46. }
  47. }
  48. + (void)swizzleMethods {
  49. [[FIRMessagingRemoteNotificationsProxy sharedProxy] swizzleMethodsIfPossible];
  50. }
  51. + (instancetype)sharedProxy {
  52. static FIRMessagingRemoteNotificationsProxy *proxy;
  53. static dispatch_once_t onceToken;
  54. dispatch_once(&onceToken, ^{
  55. proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
  56. });
  57. return proxy;
  58. }
  59. - (instancetype)init {
  60. self = [super init];
  61. if (self) {
  62. _originalAppDelegateImps = [[NSMutableDictionary alloc] init];
  63. _swizzledSelectorsByClass = [[NSMutableDictionary alloc] init];
  64. }
  65. return self;
  66. }
  67. - (void)dealloc {
  68. [self unswizzleAllMethods];
  69. self.swizzledSelectorsByClass = nil;
  70. [self.originalAppDelegateImps removeAllObjects];
  71. self.originalAppDelegateImps = nil;
  72. [self removeUserNotificationCenterDelegateObserver];
  73. }
  74. - (void)swizzleMethodsIfPossible {
  75. // Already swizzled.
  76. if (self.didSwizzleMethods) {
  77. return;
  78. }
  79. NSObject<UIApplicationDelegate> *appDelegate = [[UIApplication sharedApplication] delegate];
  80. [self swizzleAppDelegateMethods:appDelegate];
  81. // Add KVO listener on [UNUserNotificationCenter currentNotificationCenter]'s delegate property
  82. Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
  83. if (notificationCenterClass) {
  84. // We are linked against iOS 10 SDK or above
  85. id notificationCenter = getNamedPropertyFromObject(notificationCenterClass,
  86. @"currentNotificationCenter",
  87. notificationCenterClass);
  88. if (notificationCenter) {
  89. [self listenForDelegateChangesInUserNotificationCenter:notificationCenter];
  90. }
  91. }
  92. self.didSwizzleMethods = YES;
  93. }
  94. - (void)unswizzleAllMethods {
  95. for (NSString *className in self.swizzledSelectorsByClass) {
  96. Class klass = NSClassFromString(className);
  97. NSArray *selectorStrings = self.swizzledSelectorsByClass[className];
  98. for (NSString *selectorString in selectorStrings) {
  99. SEL selector = NSSelectorFromString(selectorString);
  100. [self unswizzleSelector:selector inClass:klass];
  101. }
  102. }
  103. [self.swizzledSelectorsByClass removeAllObjects];
  104. }
  105. - (void)swizzleAppDelegateMethods:(id<UIApplicationDelegate>)appDelegate {
  106. if (![appDelegate conformsToProtocol:@protocol(UIApplicationDelegate)]) {
  107. return;
  108. }
  109. Class appDelegateClass = [appDelegate class];
  110. BOOL didSwizzleAppDelegate = NO;
  111. // Message receiving handler for iOS 9, 8, 7 devices (both display notification and data message).
  112. SEL remoteNotificationSelector =
  113. @selector(application:didReceiveRemoteNotification:);
  114. SEL remoteNotificationWithFetchHandlerSelector =
  115. @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
  116. // For data message from MCS.
  117. SEL receiveDataMessageSelector = NSSelectorFromString(@"applicationReceivedRemoteMessage:");
  118. // For recording when APNS tokens are registered (or fail to register)
  119. SEL registerForAPNSFailSelector =
  120. @selector(application:didFailToRegisterForRemoteNotificationsWithError:);
  121. SEL registerForAPNSSuccessSelector =
  122. @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);
  123. // Receive Remote Notifications.
  124. BOOL selectorWithFetchHandlerImplemented = NO;
  125. if ([appDelegate respondsToSelector:remoteNotificationWithFetchHandlerSelector]) {
  126. selectorWithFetchHandlerImplemented = YES;
  127. [self swizzleSelector:remoteNotificationWithFetchHandlerSelector
  128. inClass:appDelegateClass
  129. withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotificationWithHandler
  130. inProtocol:@protocol(UIApplicationDelegate)];
  131. didSwizzleAppDelegate = YES;
  132. }
  133. if ([appDelegate respondsToSelector:remoteNotificationSelector] ||
  134. !selectorWithFetchHandlerImplemented) {
  135. [self swizzleSelector:remoteNotificationSelector
  136. inClass:appDelegateClass
  137. withImplementation:(IMP)FCM_swizzle_appDidReceiveRemoteNotification
  138. inProtocol:@protocol(UIApplicationDelegate)];
  139. didSwizzleAppDelegate = YES;
  140. }
  141. if ([appDelegate respondsToSelector:receiveDataMessageSelector]) {
  142. [self swizzleSelector:receiveDataMessageSelector
  143. inClass:appDelegateClass
  144. withImplementation:(IMP)FCM_swizzle_applicationReceivedRemoteMessage
  145. inProtocol:@protocol(UIApplicationDelegate)];
  146. didSwizzleAppDelegate = YES;
  147. }
  148. // Receive APNS token
  149. [self swizzleSelector:registerForAPNSSuccessSelector
  150. inClass:appDelegateClass
  151. withImplementation:(IMP)FCM_swizzle_appDidRegisterForRemoteNotifications
  152. inProtocol:@protocol(UIApplicationDelegate)];
  153. [self swizzleSelector:registerForAPNSFailSelector
  154. inClass:appDelegateClass
  155. withImplementation:(IMP)FCM_swizzle_appDidFailToRegisterForRemoteNotifications
  156. inProtocol:@protocol(UIApplicationDelegate)];
  157. self.didSwizzleAppDelegateMethods = didSwizzleAppDelegate;
  158. }
  159. - (void)listenForDelegateChangesInUserNotificationCenter:(id)notificationCenter {
  160. Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
  161. if (![notificationCenter isKindOfClass:notificationCenterClass]) {
  162. return;
  163. }
  164. id delegate = getNamedPropertyFromObject(notificationCenter, @"delegate", nil);
  165. Protocol *delegateProtocol = NSProtocolFromString(@"UNUserNotificationCenterDelegate");
  166. if ([delegate conformsToProtocol:delegateProtocol]) {
  167. // Swizzle this object now, if available
  168. [self swizzleUserNotificationCenterDelegate:delegate];
  169. }
  170. // Add KVO observer for "delegate" keyPath for future changes
  171. [self addDelegateObserverToUserNotificationCenter:notificationCenter];
  172. }
  173. #pragma mark - UNNotificationCenter Swizzling
  174. - (void)swizzleUserNotificationCenterDelegate:(id)delegate {
  175. if (self.currentUserNotificationCenterDelegate == delegate) {
  176. // Via pointer-check, compare if we have already swizzled this item.
  177. return;
  178. }
  179. Protocol *userNotificationCenterProtocol =
  180. NSProtocolFromString(@"UNUserNotificationCenterDelegate");
  181. if ([delegate conformsToProtocol:userNotificationCenterProtocol]) {
  182. SEL willPresentNotificationSelector =
  183. NSSelectorFromString(kUserNotificationWillPresentSelectorString);
  184. [self swizzleSelector:willPresentNotificationSelector
  185. inClass:[delegate class]
  186. withImplementation:(IMP)FCM_swizzle_willPresentNotificationWithHandler
  187. inProtocol:userNotificationCenterProtocol];
  188. self.currentUserNotificationCenterDelegate = delegate;
  189. self.hasSwizzledUserNotificationDelegate = YES;
  190. }
  191. }
  192. - (void)unswizzleUserNotificationCenterDelegate:(id)delegate {
  193. if (self.currentUserNotificationCenterDelegate != delegate) {
  194. // We aren't swizzling this delegate, so don't do anything.
  195. return;
  196. }
  197. SEL willPresentNotificationSelector =
  198. NSSelectorFromString(kUserNotificationWillPresentSelectorString);
  199. [self unswizzleSelector:willPresentNotificationSelector
  200. inClass:[self.currentUserNotificationCenterDelegate class]];
  201. self.currentUserNotificationCenterDelegate = nil;
  202. self.hasSwizzledUserNotificationDelegate = NO;
  203. }
  204. #pragma mark - KVO for UNUserNotificationCenter
  205. - (void)addDelegateObserverToUserNotificationCenter:(id)userNotificationCenter {
  206. [self removeUserNotificationCenterDelegateObserver];
  207. @try {
  208. [userNotificationCenter addObserver:self
  209. forKeyPath:NSStringFromSelector(@selector(delegate))
  210. options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
  211. context:UserNotificationObserverContext];
  212. self.userNotificationCenter = userNotificationCenter;
  213. self.isObservingUserNotificationDelegateChanges = YES;
  214. } @catch (NSException *exception) {
  215. FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy000,
  216. @"Encountered exception trying to add a KVO observer for "
  217. @"UNUserNotificationCenter's 'delegate' property: %@",
  218. exception);
  219. } @finally {
  220. }
  221. }
  222. - (void)removeUserNotificationCenterDelegateObserver {
  223. if (!self.userNotificationCenter) {
  224. return;
  225. }
  226. @try {
  227. [self.userNotificationCenter removeObserver:self
  228. forKeyPath:NSStringFromSelector(@selector(delegate))
  229. context:UserNotificationObserverContext];
  230. self.userNotificationCenter = nil;
  231. self.isObservingUserNotificationDelegateChanges = NO;
  232. } @catch (NSException *exception) {
  233. FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy001,
  234. @"Encountered exception trying to remove a KVO observer for "
  235. @"UNUserNotificationCenter's 'delegate' property: %@",
  236. exception);
  237. } @finally {
  238. }
  239. }
  240. - (void)observeValueForKeyPath:(NSString *)keyPath
  241. ofObject:(id)object
  242. change:(NSDictionary<NSKeyValueChangeKey, id> *)change
  243. context:(void *)context {
  244. if (context == UserNotificationObserverContext) {
  245. if ([keyPath isEqualToString:NSStringFromSelector(@selector(delegate))]) {
  246. id oldDelegate = change[NSKeyValueChangeOldKey];
  247. if (oldDelegate && oldDelegate != [NSNull null]) {
  248. [self unswizzleUserNotificationCenterDelegate:oldDelegate];
  249. }
  250. id newDelegate = change[NSKeyValueChangeNewKey];
  251. if (newDelegate && newDelegate != [NSNull null]) {
  252. [self swizzleUserNotificationCenterDelegate:newDelegate];
  253. }
  254. }
  255. } else {
  256. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  257. }
  258. }
  259. #pragma mark - NSProxy methods
  260. - (void)saveOriginalImplementation:(IMP)imp forSelector:(SEL)selector {
  261. if (imp && selector) {
  262. NSValue *IMPValue = [NSValue valueWithPointer:imp];
  263. NSString *selectorString = NSStringFromSelector(selector);
  264. self.originalAppDelegateImps[selectorString] = IMPValue;
  265. }
  266. }
  267. - (IMP)originalImplementationForSelector:(SEL)selector {
  268. NSString *selectorString = NSStringFromSelector(selector);
  269. NSValue *implementation_value = self.originalAppDelegateImps[selectorString];
  270. if (!implementation_value) {
  271. return nil;
  272. }
  273. IMP imp;
  274. [implementation_value getValue:&imp];
  275. return imp;
  276. }
  277. - (void)trackSwizzledSelector:(SEL)selector ofClass:(Class)klass {
  278. NSString *className = NSStringFromClass(klass);
  279. NSString *selectorString = NSStringFromSelector(selector);
  280. NSArray *selectors = self.swizzledSelectorsByClass[selectorString];
  281. if (selectors) {
  282. selectors = [selectors arrayByAddingObject:selectorString];
  283. } else {
  284. selectors = @[selectorString];
  285. }
  286. self.swizzledSelectorsByClass[className] = selectors;
  287. }
  288. - (void)removeImplementationForSelector:(SEL)selector {
  289. NSString *selectorString = NSStringFromSelector(selector);
  290. [self.originalAppDelegateImps removeObjectForKey:selectorString];
  291. }
  292. - (void)swizzleSelector:(SEL)originalSelector
  293. inClass:(Class)klass
  294. withImplementation:(IMP)swizzledImplementation
  295. inProtocol:(Protocol *)protocol {
  296. Method originalMethod = class_getInstanceMethod(klass, originalSelector);
  297. if (originalMethod) {
  298. // This class implements this method, so replace the original implementation
  299. // with our new implementation and save the old implementation.
  300. IMP __original_method_implementation =
  301. method_setImplementation(originalMethod, swizzledImplementation);
  302. IMP __nonexistant_method_implementation = [self nonExistantMethodImplementationForClass:klass];
  303. if (__original_method_implementation &&
  304. __original_method_implementation != __nonexistant_method_implementation &&
  305. __original_method_implementation != swizzledImplementation) {
  306. [self saveOriginalImplementation:__original_method_implementation
  307. forSelector:originalSelector];
  308. }
  309. } else {
  310. // The class doesn't have this method, so add our swizzled implementation as the
  311. // original implementation of the original method.
  312. struct objc_method_description method_description =
  313. protocol_getMethodDescription(protocol, originalSelector, NO, YES);
  314. class_addMethod(klass,
  315. originalSelector,
  316. swizzledImplementation,
  317. method_description.types);
  318. }
  319. [self trackSwizzledSelector:originalSelector ofClass:klass];
  320. }
  321. - (void)unswizzleSelector:(SEL)selector inClass:(Class)klass {
  322. Method swizzledMethod = class_getInstanceMethod(klass, selector);
  323. if (!swizzledMethod) {
  324. // This class doesn't seem to have this selector as an instance method? Bail out.
  325. return;
  326. }
  327. IMP original_imp = [self originalImplementationForSelector:selector];
  328. if (original_imp) {
  329. // Restore the original implementation as the current implementation
  330. method_setImplementation(swizzledMethod, original_imp);
  331. [self removeImplementationForSelector:selector];
  332. } else {
  333. // This class originally did not have an implementation for this selector.
  334. // We can't actually remove methods in Objective C 2.0, but we could set
  335. // its method to something non-existent. This should give us the same
  336. // behavior as if the method was not implemented.
  337. // See: http://stackoverflow.com/a/8276527/9849
  338. IMP nonExistantMethodImplementation = [self nonExistantMethodImplementationForClass:klass];
  339. method_setImplementation(swizzledMethod, nonExistantMethodImplementation);
  340. }
  341. }
  342. #pragma mark - Reflection Helpers
  343. // This is useful to generate from a stable, "known missing" selector, as the IMP can be compared
  344. // in case we are setting an implementation for a class that was previously "unswizzled" into a
  345. // non-existant implementation.
  346. - (IMP)nonExistantMethodImplementationForClass:(Class)klass {
  347. SEL nonExistantSelector = NSSelectorFromString(@"aNonExistantMethod");
  348. IMP nonExistantMethodImplementation = class_getMethodImplementation(klass, nonExistantSelector);
  349. return nonExistantMethodImplementation;
  350. }
  351. // A safe, non-leaky way return a property object by its name
  352. id getNamedPropertyFromObject(id object, NSString *propertyName, Class klass) {
  353. SEL selector = NSSelectorFromString(propertyName);
  354. if (![object respondsToSelector:selector]) {
  355. return nil;
  356. }
  357. if (!klass) {
  358. klass = [NSObject class];
  359. }
  360. // Suppress clang warning about leaks in performSelector
  361. // The alternative way to perform this is to invoke
  362. // the method as a block (see http://stackoverflow.com/a/20058585),
  363. // but this approach sometimes returns incomplete objects.
  364. #pragma clang diagnostic push
  365. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  366. id property = [object performSelector:selector];
  367. #pragma clang diagnostic pop
  368. if (![property isKindOfClass:klass]) {
  369. return nil;
  370. }
  371. return property;
  372. }
  373. #pragma mark - Swizzled Methods
  374. void FCM_swizzle_appDidReceiveRemoteNotification(id self,
  375. SEL _cmd,
  376. UIApplication *app,
  377. NSDictionary *userInfo) {
  378. [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
  379. IMP original_imp =
  380. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  381. if (original_imp) {
  382. ((void (*)(id, SEL, UIApplication *, NSDictionary *))original_imp)(self,
  383. _cmd,
  384. app,
  385. userInfo);
  386. }
  387. }
  388. void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler(
  389. id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
  390. void (^handler)(UIBackgroundFetchResult)) {
  391. [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
  392. IMP original_imp =
  393. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  394. if (original_imp) {
  395. ((void (*)(id, SEL, UIApplication *, NSDictionary *,
  396. void (^)(UIBackgroundFetchResult)))original_imp)(
  397. self, _cmd, app, userInfo, handler);
  398. }
  399. }
  400. /**
  401. * Swizzle the notification handler for iOS 10+ devices.
  402. * Signature of original handler is as below:
  403. * - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  404. * willPresentNotification:(UNNotification *)notification
  405. * withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
  406. * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
  407. * parameter types from the swizzling implementation.
  408. */
  409. void FCM_swizzle_willPresentNotificationWithHandler(
  410. id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger)) {
  411. FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
  412. IMP original_imp = [proxy originalImplementationForSelector:_cmd];
  413. void (^callOriginalMethodIfAvailable)() = ^{
  414. if (original_imp) {
  415. ((void (*)(id, SEL, id, id, void (^)(NSUInteger)))original_imp)(
  416. self, _cmd, center, notification, handler);
  417. }
  418. return;
  419. };
  420. Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
  421. Class notificationClass = NSClassFromString(@"UNNotification");
  422. if (!notificationCenterClass || !notificationClass) {
  423. // Can't find UserNotifications framework. Do not swizzle, just execute the original method.
  424. callOriginalMethodIfAvailable();
  425. }
  426. if (!center || ![center isKindOfClass:[notificationCenterClass class]]) {
  427. // Invalid parameter type from the original method.
  428. // Do not swizzle, just execute the original method.
  429. callOriginalMethodIfAvailable();
  430. return;
  431. }
  432. if (!notification || ![notification isKindOfClass:[notificationClass class]]) {
  433. // Invalid parameter type from the original method.
  434. // Do not swizzle, just execute the original method.
  435. callOriginalMethodIfAvailable();
  436. return;
  437. }
  438. if (!handler) {
  439. // Invalid parameter type from the original method.
  440. // Do not swizzle, just execute the original method.
  441. callOriginalMethodIfAvailable();
  442. return;
  443. }
  444. // Valid original method signature, go ahead to swizzle.
  445. // Select the userInfo field from UNNotification.request.content.userInfo.
  446. SEL requestSelector = NSSelectorFromString(@"request");
  447. if (![notification respondsToSelector:requestSelector]) {
  448. // This is not the expected notification handler. Do not swizzle, just execute the original
  449. // method.
  450. callOriginalMethodIfAvailable();
  451. return;
  452. }
  453. Class requestClass = NSClassFromString(@"UNNotificationRequest");
  454. id notificationRequest = getNamedPropertyFromObject(notification, @"request", requestClass);
  455. SEL notificationContentSelector = NSSelectorFromString(@"content");
  456. if (!notificationRequest
  457. || ![notificationRequest respondsToSelector:notificationContentSelector]) {
  458. // This is not the expected notification handler. Do not swizzle, just execute the original
  459. // method.
  460. callOriginalMethodIfAvailable();
  461. return;
  462. }
  463. Class contentClass = NSClassFromString(@"UNNotificationContent");
  464. id notificationContent = getNamedPropertyFromObject(notificationRequest,
  465. @"content",
  466. contentClass);
  467. SEL notificationUserInfoSelector = NSSelectorFromString(@"userInfo");
  468. if (!notificationContent
  469. || ![notificationContent respondsToSelector:notificationUserInfoSelector]) {
  470. // This is not the expected notification handler. Do not swizzle, just execute the original
  471. // method.
  472. callOriginalMethodIfAvailable();
  473. return;
  474. }
  475. id notificationUserInfo = getNamedPropertyFromObject(notificationContent,
  476. @"userInfo",
  477. [NSDictionary class]);
  478. if (!notificationUserInfo) {
  479. // This is not the expected notification handler. Do not swizzle, just execute the original
  480. // method.
  481. callOriginalMethodIfAvailable();
  482. return;
  483. }
  484. [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
  485. // Execute the original implementation.
  486. callOriginalMethodIfAvailable();
  487. }
  488. void FCM_swizzle_applicationReceivedRemoteMessage(
  489. id self, SEL _cmd, FIRMessagingRemoteMessage *remoteMessage) {
  490. [[FIRMessaging messaging] appDidReceiveMessage:remoteMessage.appData];
  491. IMP original_imp =
  492. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  493. if (original_imp) {
  494. ((void (*)(id, SEL, FIRMessagingRemoteMessage *))original_imp)(self, _cmd, remoteMessage);
  495. }
  496. }
  497. void FCM_swizzle_appDidFailToRegisterForRemoteNotifications(id self,
  498. SEL _cmd,
  499. UIApplication *app,
  500. NSError *error) {
  501. // Log the fact that we failed to register for remote notifications
  502. FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed,
  503. @"Error in "
  504. @"application:didFailToRegisterForRemoteNotificationsWithError: %@",
  505. error.localizedDescription);
  506. IMP original_imp =
  507. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  508. if (original_imp) {
  509. ((void (*)(id, SEL, UIApplication *, NSError *))original_imp)(self, _cmd, app, error);
  510. }
  511. }
  512. void FCM_swizzle_appDidRegisterForRemoteNotifications(id self,
  513. SEL _cmd,
  514. UIApplication *app,
  515. NSData *deviceToken) {
  516. // Pass the APNSToken along to FIRMessaging (and auto-detect the token type)
  517. [FIRMessaging messaging].APNSToken = deviceToken;
  518. IMP original_imp =
  519. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  520. if (original_imp) {
  521. ((void (*)(id, SEL, UIApplication *, NSData *))original_imp)(self, _cmd, app, deviceToken);
  522. }
  523. }
  524. @end