diff options
-rw-r--r-- | Example/Messaging/App/iOS/AppDelegate.swift | 21 | ||||
-rw-r--r-- | Firebase/Messaging/FIRMMessageCode.h | 1 | ||||
-rw-r--r-- | Firebase/Messaging/FIRMessaging.m | 76 | ||||
-rw-r--r-- | Firebase/Messaging/Public/FIRMessaging.h | 40 |
4 files changed, 99 insertions, 39 deletions
diff --git a/Example/Messaging/App/iOS/AppDelegate.swift b/Example/Messaging/App/iOS/AppDelegate.swift index aafd844..32b55ed 100644 --- a/Example/Messaging/App/iOS/AppDelegate.swift +++ b/Example/Messaging/App/iOS/AppDelegate.swift @@ -66,19 +66,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // register for remote notifications NotificationsController.shared.registerForUserFacingNotificationsFor(application) } - - printFCMToken() return true } - func printFCMToken() { - if let token = Messaging.messaging().fcmToken { - print("FCM Token: \(token)") - } else { - print("FCM Token: nil") - } - } - func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { print("APNS Token: \(deviceToken.hexByteString)") @@ -116,8 +106,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } extension AppDelegate: MessagingDelegate { - func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) { - printFCMToken() + // FCM tokens are always provided here. It is called generally during app start, but may be called + // more than once, if the token is invalidated or updated. This is the right spot to upload this + // token to your application server, or to subscribe to any topics. + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { + if let token = Messaging.messaging().fcmToken { + print("FCM Token: \(token)") + } else { + print("FCM Token: nil") + } } // Direct channel data messages are delivered here, on iOS 10.0+. diff --git a/Firebase/Messaging/FIRMMessageCode.h b/Firebase/Messaging/FIRMMessageCode.h index 46505ec..2b6ddad 100644 --- a/Firebase/Messaging/FIRMMessageCode.h +++ b/Firebase/Messaging/FIRMMessageCode.h @@ -44,6 +44,7 @@ typedef NS_ENUM(NSInteger, FIRMessagingMessageCode) { kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenFetch = 2020, // I-FCM002020 kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenDelete = 2021, // I-FCM002021 kFIRMessagingMessageCodeAPNSTokenNotAvailableDuringTokenFetch = 2022, // I-FCM002022 + kFIRMessagingMessageCodeTokenDelegateMethodsNotImplemented = 2023, // I-FCM002023 // FIRMessagingClient.m kFIRMessagingMessageCodeClient000 = 4000, // I-FCM004000 kFIRMessagingMessageCodeClient001 = 4001, // I-FCM004001 diff --git a/Firebase/Messaging/FIRMessaging.m b/Firebase/Messaging/FIRMessaging.m index 9d10741..1c31961 100644 --- a/Firebase/Messaging/FIRMessaging.m +++ b/Firebase/Messaging/FIRMessaging.m @@ -507,6 +507,42 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification = handler:completion]; } +#pragma mark - FIRMessagingDelegate helper methods +- (void)setDelegate:(id<FIRMessagingDelegate>)delegate { + _delegate = delegate; + [self validateDelegateConformsToTokenAvailabilityMethods]; +} + +// Check if the delegate conforms to either |didReceiveRegistrationToken:| or +// |didRefreshRegistrationToken:|, and display a warning to the developer if not. +// NOTE: Once |didReceiveRegistrationToken:| can be made a required method, this +// check can be removed. +- (void)validateDelegateConformsToTokenAvailabilityMethods { + if (self.delegate && + ![self.delegate respondsToSelector:@selector(messaging:didReceiveRegistrationToken:)] && + ![self.delegate respondsToSelector:@selector(messaging:didRefreshRegistrationToken:)]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTokenDelegateMethodsNotImplemented, + @"The object %@ does not respond to " + @"-messaging:didReceiveRegistrationToken:, nor " + @"-messaging:didRefreshRegistrationToken:. Please implement " + @"-messaging:didReceiveRegistrationToken: to be provided with an FCM " + @"token.", self.delegate.description); + } +} + +- (void)notifyDelegateOfFCMTokenAvailability { + __weak FIRMessaging *weakSelf = self; + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf notifyDelegateOfFCMTokenAvailability]; + }); + return; + } + if ([self.delegate respondsToSelector:@selector(messaging:didReceiveRegistrationToken:)]) { + [self.delegate messaging:self didReceiveRegistrationToken:self.defaultFcmToken]; + } +} + #pragma mark - Application State Changes - (void)applicationStateChanged { @@ -719,6 +755,17 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification = #pragma mark - Network +- (void)onNetworkStatusChanged { + if (![self.client isConnected] && [self isNetworkAvailable]) { + if (self.client.shouldStayConnected) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging014, + @"Attempting to establish direct channel."); + [self.client retryConnectionImmediately:YES]; + } + [self.pubsub scheduleSync:YES]; + } +} + - (BOOL)isNetworkAvailable { FIRReachabilityStatus status = self.reachability.reachabilityStatus; return (status == kFIRReachabilityViaCellular || status == kFIRReachabilityViaWifi); @@ -737,19 +784,6 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification = #pragma mark - Notifications -- (void)onNetworkStatusChanged { - if (![self.client isConnected] && [self isNetworkAvailable]) { - if (self.client.shouldStayConnected) { - FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging014, - @"Attempting to establish direct channel."); - [self.client retryConnectionImmediately:YES]; - } - [self.pubsub scheduleSync:YES]; - } -} - -#pragma mark - Notifications - - (void)didReceiveDefaultInstanceIDToken:(NSNotification *)notification { if (![notification.object isKindOfClass:[NSString class]]) { FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging015, @@ -757,7 +791,11 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification = NSStringFromClass([notification.object class])); return; } + NSString *oldToken = self.defaultFcmToken; self.defaultFcmToken = [(NSString *)notification.object copy]; + if (self.defaultFcmToken && ![self.defaultFcmToken isEqualToString:oldToken]) { + [self notifyDelegateOfFCMTokenAvailability]; + } [self.pubsub scheduleSync:YES]; if (self.shouldEstablishDirectChannel) { [self updateAutomaticClientConnection]; @@ -771,8 +809,18 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification = // token is fetched, and then notify. This ensures that this token should not // be nil when the developer accesses it. if (token != nil) { + NSString *oldToken = self.defaultFcmToken; self.defaultFcmToken = [token copy]; - [self.delegate messaging:self didRefreshRegistrationToken:token]; + if (self.defaultFcmToken && ![self.defaultFcmToken isEqualToString:oldToken]) { + [self notifyDelegateOfFCMTokenAvailability]; + } + // Call deprecated refresh method, because it should still work (until it is removed). +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if ([self.delegate respondsToSelector:@selector(messaging:didRefreshRegistrationToken:)]) { + [self.delegate messaging:self didRefreshRegistrationToken:token]; + } +#pragma clang diagnostic pop NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center postNotificationName:FIRMessagingRegistrationTokenRefreshedNotification object:nil]; } diff --git a/Firebase/Messaging/Public/FIRMessaging.h b/Firebase/Messaging/Public/FIRMessaging.h index 7313f23..65a9d06 100644 --- a/Firebase/Messaging/Public/FIRMessaging.h +++ b/Firebase/Messaging/Public/FIRMessaging.h @@ -111,9 +111,9 @@ FOUNDATION_EXPORT const NSNotificationName __nonnull FIRMessagingConnectionState FIR_SWIFT_NAME(MessagingConnectionStateChanged); /** - * Notification sent when the FCM registration token has been refreshed. You can also - * receive the FCM token via the FIRMessagingDelegate method - * `-messaging:didRefreshRegistrationToken:` + * Notification sent when the FCM registration token has been refreshed. Please use the + * FIRMessaging delegate method `messaging:didReceiveRegistrationToken:` to receive current and + * updated tokens. */ FOUNDATION_EXPORT const NSNotificationName __nonnull FIRMessagingRegistrationTokenRefreshedNotification @@ -156,9 +156,9 @@ FOUNDATION_EXPORT NSString * __nonnull const FIRMessagingConnectionStateChangedN FIR_SWIFT_NAME(MessagingConnectionStateChangedNotification); /** - * Notification sent when the FCM registration token has been refreshed. You can also - * receive the FCM token via the FIRMessagingDelegate method - * `-messaging:didRefreshRegistrationToken:` + * Notification sent when the FCM registration token has been refreshed. Please use the + * FIRMessaging delegate method `messaging:didReceiveRegistrationToken:` to receive current and + * updated tokens. */ FOUNDATION_EXPORT NSString * __nonnull const FIRMessagingRegistrationTokenRefreshedNotification FIR_SWIFT_NAME(MessagingRegistrationTokenRefreshedNotification); @@ -246,14 +246,27 @@ FIR_SWIFT_NAME(MessagingRemoteMessage) FIR_SWIFT_NAME(MessagingDelegate) @protocol FIRMessagingDelegate <NSObject> +@optional +/// This method will be called once a token is available, or has been refreshed. Typically it +/// will be called once per app start, but may be called more often, if token is invalidated or +/// updated. In this method, you should perform operations such as: +/// +/// * Uploading the FCM token to your application server, so targeted notifications can be sent. +/// +/// * Subscribing to any topics. +- (void)messaging:(nonnull FIRMessaging *)messaging + didReceiveRegistrationToken:(nonnull NSString *)fcmToken + FIR_SWIFT_NAME(messaging(_:didReceiveRegistrationToken:)); + /// This method will be called whenever FCM receives a new, default FCM token for your -/// Firebase project's Sender ID. -/// You can send this token to your application server to send notifications to this device. +/// Firebase project's Sender ID. This method is deprecated. Please use +/// `messaging:didReceiveRegistrationToken:`. - (void)messaging:(nonnull FIRMessaging *)messaging didRefreshRegistrationToken:(nonnull NSString *)fcmToken - FIR_SWIFT_NAME(messaging(_:didRefreshRegistrationToken:)); + FIR_SWIFT_NAME(messaging(_:didRefreshRegistrationToken:)) + __deprecated_msg("Please use messaging:didReceiveRegistrationToken:, which is called for both \ + current and refreshed tokens."); -@optional /// This method is called on iOS 10 devices to handle data messages received via FCM through its /// direct channel (not via APNS). For iOS 9 and below, the FCM data message is delivered via the /// UIApplicationDelegate's -application:didReceiveRemoteNotification: method. @@ -356,9 +369,10 @@ FIR_SWIFT_NAME(Messaging) * It is associated with your APNS token when the APNS token is supplied, so that sending * messages to the FCM token will be delivered over APNS. * - * The FCM token is sometimes refreshed automatically. You can be notified of these changes - * via the FIRMessagingDelegate method `-message:didRefreshRegistrationToken:`, or by - * listening for the `FIRMessagingRegistrationTokenRefreshedNotification` notification. + * The FCM token is sometimes refreshed automatically. In your FIRMessaging delegate, the + * delegate method `messaging:didReceiveRegistrationToken:` will be called once a token is + * available, or has been refreshed. Typically it should be called once per app start, but + * may be called more often, if token is invalidated or updated. * * Once you have an FCM token, you should send it to your application server, so it can use * the FCM token to send notifications to your device. |