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 "FIRMessagingReceiver.h"
19 #import <UIKit/UIKit.h>
21 #import "FIRMessaging.h"
22 #import "FIRMessagingLogger.h"
23 #import "FIRMessagingUtilities.h"
24 #import "FIRMessaging_Private.h"
26 static NSString *const kUpstreamMessageIDUserInfoKey = @"messageID";
27 static NSString *const kUpstreamErrorUserInfoKey = @"error";
29 // Copied from Apple's header in case it is missing in some cases.
30 #ifndef NSFoundationVersionNumber_iOS_9_x_Max
31 #define NSFoundationVersionNumber_iOS_9_x_Max 1299
34 static int downstreamMessageID = 0;
36 @implementation FIRMessagingReceiver
38 #pragma mark - FIRMessagingDataMessageManager protocol
40 - (void)didReceiveMessage:(NSDictionary *)message withIdentifier:(nullable NSString *)messageID {
41 if (![messageID length]) {
42 messageID = [[self class] nextMessageID];
45 if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) {
46 // Use delegate method for iOS 10
47 [self scheduleIos10NotificationForMessage:message withIdentifier:messageID];
49 // Post notification directly to AppDelegate handlers. This is valid pre-iOS 10.
50 [self scheduleNotificationForMessage:message];
54 - (void)willSendDataMessageWithID:(NSString *)messageID error:(NSError *)error {
55 NSNotification *notification;
57 NSDictionary *userInfo = @{
58 kUpstreamMessageIDUserInfoKey : [messageID copy],
59 kUpstreamErrorUserInfoKey : error
61 notification = [NSNotification notificationWithName:FIRMessagingSendErrorNotification
64 [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
65 FIRMessagingLoggerDebug(kFIRMessagingMessageCodeReceiver000,
66 @"Fail to send upstream message: %@ error: %@", messageID, error);
68 FIRMessagingLoggerDebug(kFIRMessagingMessageCodeReceiver001, @"Will send upstream message: %@",
73 - (void)didSendDataMessageWithID:(NSString *)messageID {
74 // invoke the callbacks asynchronously
75 FIRMessagingLoggerDebug(kFIRMessagingMessageCodeReceiver002, @"Did send upstream message: %@",
77 NSNotification * notification =
78 [NSNotification notificationWithName:FIRMessagingSendSuccessNotification
80 userInfo:@{ kUpstreamMessageIDUserInfoKey : [messageID copy] }];
82 [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
85 - (void)didDeleteMessagesOnServer {
86 FIRMessagingLoggerDebug(kFIRMessagingMessageCodeReceiver003,
87 @"Will send deleted messages notification");
88 NSNotification * notification =
89 [NSNotification notificationWithName:FIRMessagingMessagesDeletedNotification
92 [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
95 #pragma mark - Private Helpers
96 // As the new UserNotifications framework in iOS 10 doesn't support constructor/mutation for
97 // UNNotification object, FCM can't inject the message to the app with UserNotifications framework.
98 // Define our own protocol, which means app developers need to implement two interfaces to receive
99 // display notifications and data messages respectively for devices running iOS 10 or above. Devices
100 // running iOS 9 or below are not affected.
101 - (void)scheduleIos10NotificationForMessage:(NSDictionary *)message
102 withIdentifier:(NSString *)messageID {
103 FIRMessagingRemoteMessage *wrappedMessage = [[FIRMessagingRemoteMessage alloc] init];
104 // TODO: wrap title, body, badge and other fields
105 wrappedMessage.appData = [message copy];
106 [self.delegate receiver:self receivedRemoteMessage:wrappedMessage];
109 - (void)scheduleNotificationForMessage:(NSDictionary *)message {
110 SEL newNotificationSelector =
111 @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
112 SEL oldNotificationSelector = @selector(application:didReceiveRemoteNotification:);
114 dispatch_async(dispatch_get_main_queue(), ^{
115 UIApplication *application = FIRMessagingUIApplication();
119 id<UIApplicationDelegate> appDelegate = [application delegate];
120 if ([appDelegate respondsToSelector:newNotificationSelector]) {
121 // Try the new remote notification callback
122 [appDelegate application:application
123 didReceiveRemoteNotification:message
124 fetchCompletionHandler:^(UIBackgroundFetchResult result) {
127 } else if ([appDelegate respondsToSelector:oldNotificationSelector]) {
128 // Try the old remote notification callback
129 #pragma clang diagnostic push
130 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
131 [appDelegate application:application didReceiveRemoteNotification:message];
132 #pragma clang diagnostic pop
134 FIRMessagingLoggerError(kFIRMessagingMessageCodeReceiver005,
135 @"None of the remote notification callbacks implemented by "
136 @"UIApplicationDelegate");
141 + (NSString *)nextMessageID {
142 @synchronized (self) {
143 ++downstreamMessageID;
144 return [NSString stringWithFormat:@"gcm-%d", downstreamMessageID];