FIRMessagingRemoteNotificationsProxy.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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. BOOL methodAdded = class_addMethod(klass,
  315. originalSelector,
  316. swizzledImplementation,
  317. method_description.types);
  318. if (!methodAdded) {
  319. FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyMethodNotAdded,
  320. @"Could not add method for %@ to class %@",
  321. NSStringFromSelector(originalSelector),
  322. NSStringFromClass(klass));
  323. }
  324. }
  325. [self trackSwizzledSelector:originalSelector ofClass:klass];
  326. }
  327. - (void)unswizzleSelector:(SEL)selector inClass:(Class)klass {
  328. Method swizzledMethod = class_getInstanceMethod(klass, selector);
  329. if (!swizzledMethod) {
  330. // This class doesn't seem to have this selector as an instance method? Bail out.
  331. return;
  332. }
  333. IMP original_imp = [self originalImplementationForSelector:selector];
  334. if (original_imp) {
  335. // Restore the original implementation as the current implementation
  336. method_setImplementation(swizzledMethod, original_imp);
  337. [self removeImplementationForSelector:selector];
  338. } else {
  339. // This class originally did not have an implementation for this selector.
  340. // We can't actually remove methods in Objective C 2.0, but we could set
  341. // its method to something non-existent. This should give us the same
  342. // behavior as if the method was not implemented.
  343. // See: http://stackoverflow.com/a/8276527/9849
  344. IMP nonExistantMethodImplementation = [self nonExistantMethodImplementationForClass:klass];
  345. method_setImplementation(swizzledMethod, nonExistantMethodImplementation);
  346. }
  347. }
  348. #pragma mark - Reflection Helpers
  349. // This is useful to generate from a stable, "known missing" selector, as the IMP can be compared
  350. // in case we are setting an implementation for a class that was previously "unswizzled" into a
  351. // non-existant implementation.
  352. - (IMP)nonExistantMethodImplementationForClass:(Class)klass {
  353. SEL nonExistantSelector = NSSelectorFromString(@"aNonExistantMethod");
  354. IMP nonExistantMethodImplementation = class_getMethodImplementation(klass, nonExistantSelector);
  355. return nonExistantMethodImplementation;
  356. }
  357. // A safe, non-leaky way return a property object by its name
  358. id getNamedPropertyFromObject(id object, NSString *propertyName, Class klass) {
  359. SEL selector = NSSelectorFromString(propertyName);
  360. if (![object respondsToSelector:selector]) {
  361. return nil;
  362. }
  363. if (!klass) {
  364. klass = [NSObject class];
  365. }
  366. // Suppress clang warning about leaks in performSelector
  367. // The alternative way to perform this is to invoke
  368. // the method as a block (see http://stackoverflow.com/a/20058585),
  369. // but this approach sometimes returns incomplete objects.
  370. #pragma clang diagnostic push
  371. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  372. id property = [object performSelector:selector];
  373. #pragma clang diagnostic pop
  374. if (![property isKindOfClass:klass]) {
  375. return nil;
  376. }
  377. return property;
  378. }
  379. #pragma mark - Swizzled Methods
  380. void FCM_swizzle_appDidReceiveRemoteNotification(id self,
  381. SEL _cmd,
  382. UIApplication *app,
  383. NSDictionary *userInfo) {
  384. [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
  385. IMP original_imp =
  386. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  387. if (original_imp) {
  388. ((void (*)(id, SEL, UIApplication *, NSDictionary *))original_imp)(self,
  389. _cmd,
  390. app,
  391. userInfo);
  392. }
  393. }
  394. void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler(
  395. id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
  396. void (^handler)(UIBackgroundFetchResult)) {
  397. [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
  398. IMP original_imp =
  399. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  400. if (original_imp) {
  401. ((void (*)(id, SEL, UIApplication *, NSDictionary *,
  402. void (^)(UIBackgroundFetchResult)))original_imp)(
  403. self, _cmd, app, userInfo, handler);
  404. }
  405. }
  406. /**
  407. * Swizzle the notification handler for iOS 10+ devices.
  408. * Signature of original handler is as below:
  409. * - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  410. * willPresentNotification:(UNNotification *)notification
  411. * withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
  412. * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the
  413. * parameter types from the swizzling implementation.
  414. */
  415. void FCM_swizzle_willPresentNotificationWithHandler(
  416. id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger)) {
  417. FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy];
  418. IMP original_imp = [proxy originalImplementationForSelector:_cmd];
  419. void (^callOriginalMethodIfAvailable)() = ^{
  420. if (original_imp) {
  421. ((void (*)(id, SEL, id, id, void (^)(NSUInteger)))original_imp)(
  422. self, _cmd, center, notification, handler);
  423. }
  424. return;
  425. };
  426. Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter");
  427. Class notificationClass = NSClassFromString(@"UNNotification");
  428. if (!notificationCenterClass || !notificationClass) {
  429. // Can't find UserNotifications framework. Do not swizzle, just execute the original method.
  430. callOriginalMethodIfAvailable();
  431. }
  432. if (!center || ![center isKindOfClass:[notificationCenterClass 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 (!notification || ![notification isKindOfClass:[notificationClass class]]) {
  439. // Invalid parameter type from the original method.
  440. // Do not swizzle, just execute the original method.
  441. callOriginalMethodIfAvailable();
  442. return;
  443. }
  444. if (!handler) {
  445. // Invalid parameter type from the original method.
  446. // Do not swizzle, just execute the original method.
  447. callOriginalMethodIfAvailable();
  448. return;
  449. }
  450. // Valid original method signature, go ahead to swizzle.
  451. // Select the userInfo field from UNNotification.request.content.userInfo.
  452. SEL requestSelector = NSSelectorFromString(@"request");
  453. if (![notification respondsToSelector:requestSelector]) {
  454. // This is not the expected notification handler. Do not swizzle, just execute the original
  455. // method.
  456. callOriginalMethodIfAvailable();
  457. return;
  458. }
  459. Class requestClass = NSClassFromString(@"UNNotificationRequest");
  460. id notificationRequest = getNamedPropertyFromObject(notification, @"request", requestClass);
  461. SEL notificationContentSelector = NSSelectorFromString(@"content");
  462. if (!notificationRequest
  463. || ![notificationRequest respondsToSelector:notificationContentSelector]) {
  464. // This is not the expected notification handler. Do not swizzle, just execute the original
  465. // method.
  466. callOriginalMethodIfAvailable();
  467. return;
  468. }
  469. Class contentClass = NSClassFromString(@"UNNotificationContent");
  470. id notificationContent = getNamedPropertyFromObject(notificationRequest,
  471. @"content",
  472. contentClass);
  473. SEL notificationUserInfoSelector = NSSelectorFromString(@"userInfo");
  474. if (!notificationContent
  475. || ![notificationContent respondsToSelector:notificationUserInfoSelector]) {
  476. // This is not the expected notification handler. Do not swizzle, just execute the original
  477. // method.
  478. callOriginalMethodIfAvailable();
  479. return;
  480. }
  481. id notificationUserInfo = getNamedPropertyFromObject(notificationContent,
  482. @"userInfo",
  483. [NSDictionary class]);
  484. if (!notificationUserInfo) {
  485. // This is not the expected notification handler. Do not swizzle, just execute the original
  486. // method.
  487. callOriginalMethodIfAvailable();
  488. return;
  489. }
  490. [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo];
  491. // Execute the original implementation.
  492. callOriginalMethodIfAvailable();
  493. }
  494. void FCM_swizzle_applicationReceivedRemoteMessage(
  495. id self, SEL _cmd, FIRMessagingRemoteMessage *remoteMessage) {
  496. [[FIRMessaging messaging] appDidReceiveMessage:remoteMessage.appData];
  497. IMP original_imp =
  498. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  499. if (original_imp) {
  500. ((void (*)(id, SEL, FIRMessagingRemoteMessage *))original_imp)(self, _cmd, remoteMessage);
  501. }
  502. }
  503. void FCM_swizzle_appDidFailToRegisterForRemoteNotifications(id self,
  504. SEL _cmd,
  505. UIApplication *app,
  506. NSError *error) {
  507. // Log the fact that we failed to register for remote notifications
  508. FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed,
  509. @"Error in "
  510. @"application:didFailToRegisterForRemoteNotificationsWithError: %@",
  511. error.localizedDescription);
  512. IMP original_imp =
  513. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  514. if (original_imp) {
  515. ((void (*)(id, SEL, UIApplication *, NSError *))original_imp)(self, _cmd, app, error);
  516. }
  517. }
  518. void FCM_swizzle_appDidRegisterForRemoteNotifications(id self,
  519. SEL _cmd,
  520. UIApplication *app,
  521. NSData *deviceToken) {
  522. // Pass the APNSToken along to FIRMessaging (and auto-detect the token type)
  523. [FIRMessaging messaging].APNSToken = deviceToken;
  524. IMP original_imp =
  525. [[FIRMessagingRemoteNotificationsProxy sharedProxy] originalImplementationForSelector:_cmd];
  526. if (original_imp) {
  527. ((void (*)(id, SEL, UIApplication *, NSData *))original_imp)(self, _cmd, app, deviceToken);
  528. }
  529. }
  530. @end