Преглед изворни кода

Update InstanceID to listen to a notification from Messaging (#6286)

Chen Liang пре 5 година
родитељ
комит
fbcb4a1eed

+ 4 - 0
Firebase/InstanceID/CHANGELOG.md

@@ -1,3 +1,7 @@
+# 2020-08 -- 4.6.0
+- [added] Added a new notification listening token refresh from Messaging and update the token cache in InstanceID. (#6286)
+- [fixed] Fixed an issue that token refresh notification is not triggered when use `tokenWithAuthorizedEntity:scope:options:handler` to get token. (#6286)
+
 # 2020-07 -- 4.5.1
 - [changed] Remove FIRInstanceIDURLQueryItem in favor of NSURLQueryItem. (#5835)
 

+ 49 - 11
Firebase/InstanceID/FIRInstanceID.m

@@ -302,6 +302,10 @@ static FIRInstanceID *gInstanceID;
   }
 
   FIRInstanceIDTokenHandler newHandler = ^(NSString *token, NSError *error) {
+    if (!error && [self isDefaultTokenWithAuthorizedEntity:authorizedEntity scope:scope]) {
+      // The local cache should be updated as it is critical for sending token updates.
+      self.defaultFCMToken = token;
+    }
     dispatch_async(dispatch_get_main_queue(), ^{
       handler(token, error);
     });
@@ -381,8 +385,7 @@ static FIRInstanceID *gInstanceID;
 
   FIRInstanceIDDeleteTokenHandler newHandler = ^(NSError *error) {
     // If a default token is deleted successfully, reset the defaultFCMToken too.
-    if (!error && [authorizedEntity isEqualToString:self.fcmSenderID] &&
-        [scope isEqualToString:kFIRInstanceIDDefaultTokenScope]) {
+    if (!error && [self isDefaultTokenWithAuthorizedEntity:authorizedEntity scope:scope]) {
       self.defaultFCMToken = nil;
     }
     dispatch_async(dispatch_get_main_queue(), ^{
@@ -707,6 +710,7 @@ static FIRInstanceID *gInstanceID;
                  name:kFIRInstanceIDAPNSTokenNotification
                object:nil];
   [self observeFirebaseInstallationIDChanges];
+  [self observeFirebaseMessagingTokenChanges];
 }
 
 #pragma mark - Private Helpers
@@ -763,15 +767,8 @@ static FIRInstanceID *gInstanceID;
 
   NSDictionary *instanceIDOptions = @{};
   BOOL hasFirebaseMessaging = NSClassFromString(kFIRInstanceIDFCMSDKClassString) != nil;
-  if (hasFirebaseMessaging && self.apnsTokenData) {
-    BOOL isSandboxApp = (self.apnsTokenType == FIRInstanceIDAPNSTokenTypeSandbox);
-    if (self.apnsTokenType == FIRInstanceIDAPNSTokenTypeUnknown) {
-      isSandboxApp = [self isSandboxApp];
-    }
-    instanceIDOptions = @{
-      kFIRInstanceIDTokenOptionsAPNSKey : self.apnsTokenData,
-      kFIRInstanceIDTokenOptionsAPNSIsSandboxKey : @(isSandboxApp),
-    };
+  if (hasFirebaseMessaging) {
+    instanceIDOptions = [self defaultTokenOptions];
   }
 
   FIRInstanceID_WEAKIFY(self);
@@ -871,6 +868,11 @@ static FIRInstanceID *gInstanceID;
                  });
 }
 
+- (BOOL)isDefaultTokenWithAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {
+  return [authorizedEntity isEqualToString:self.fcmSenderID] &&
+         [scope isEqualToString:kFIRInstanceIDDefaultTokenScope];
+}
+
 #pragma mark - APNS Token
 // This should only be triggered from FCM.
 - (void)notifyAPNSTokenIsSet:(NSNotification *)notification {
@@ -1117,4 +1119,40 @@ static FIRInstanceID *gInstanceID;
            object:nil];
 }
 
+- (void)observeFirebaseMessagingTokenChanges {
+  [[NSNotificationCenter defaultCenter]
+      removeObserver:self
+                name:kFIRInstanceIDMessagingUpdateTokenNotification
+              object:nil];
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(messagingTokenDidChangeNotificationReceived:)
+             name:kFIRInstanceIDMessagingUpdateTokenNotification
+           object:nil];
+}
+
+- (void)messagingTokenDidChangeNotificationReceived:(NSNotification *)notification {
+  NSString *tokenUpdatedFromMessaging = notification.object;
+  if (!tokenUpdatedFromMessaging || [tokenUpdatedFromMessaging isKindOfClass:[NSString class]]) {
+    self.defaultFCMToken = tokenUpdatedFromMessaging;
+    [self.tokenManager saveDefaultToken:tokenUpdatedFromMessaging
+                            withOptions:[self defaultTokenOptions]];
+  }
+}
+
+- (NSDictionary *)defaultTokenOptions {
+  NSDictionary *tokenOptions = @{};
+  if (self.apnsTokenData) {
+    BOOL isSandboxApp = (self.apnsTokenType == FIRInstanceIDAPNSTokenTypeSandbox);
+    if (self.apnsTokenType == FIRInstanceIDAPNSTokenTypeUnknown) {
+      isSandboxApp = [self isSandboxApp];
+    }
+    tokenOptions = @{
+      kFIRInstanceIDTokenOptionsAPNSKey : self.apnsTokenData,
+      kFIRInstanceIDTokenOptionsAPNSIsSandboxKey : @(isSandboxApp),
+    };
+  }
+  return tokenOptions;
+}
+
 @end

+ 1 - 0
Firebase/InstanceID/FIRInstanceIDAuthKeyChain.h

@@ -90,6 +90,7 @@ NS_ASSUME_NONNULL_BEGIN
         account:(NSString *)account
         handler:(nullable void (^)(NSError *))handler;
 
+- (void)setDataInCache:(NSData *)data forService:(NSString *)service account:(NSString *)account;
 @end
 
 NS_ASSUME_NONNULL_END

+ 12 - 0
Firebase/InstanceID/FIRInstanceIDAuthKeyChain.m

@@ -213,4 +213,16 @@ NSString *const kFIRInstanceIDKeychainWildcardIdentifier = @"*";
   }
 }
 
+- (void)setDataInCache:(NSData *)data forService:(NSString *)service account:(NSString *)account {
+  if (_cachedKeychainData[service]) {
+    if (_cachedKeychainData[service][account]) {
+      _cachedKeychainData[service][account] = @[ data ];
+    } else {
+      [_cachedKeychainData[service] setObject:@[ data ] forKey:account];
+    }
+  } else {
+    [_cachedKeychainData setObject:[@{account : @[ data ]} mutableCopy] forKey:service];
+  }
+}
+
 @end

+ 1 - 1
Firebase/InstanceID/FIRInstanceIDConstants.h

@@ -30,7 +30,7 @@ FOUNDATION_EXPORT NSString *const kFIRInstanceID_CMD_RST;
 FOUNDATION_EXPORT NSString *const kFIRInstanceIDCheckinFetchedNotification;
 FOUNDATION_EXPORT NSString *const kFIRInstanceIDAPNSTokenNotification;
 FOUNDATION_EXPORT NSString *const kFIRInstanceIDDefaultGCMTokenFailNotification;
-
+FOUNDATION_EXPORT NSString *const kFIRInstanceIDMessagingUpdateTokenNotification;
 FOUNDATION_EXPORT NSString *const kFIRInstanceIDIdentityInvalidatedNotification;
 
 #pragma mark - Miscellaneous

+ 2 - 1
Firebase/InstanceID/FIRInstanceIDConstants.m

@@ -24,7 +24,8 @@ NSString *const kFIRInstanceIDCheckinFetchedNotification = @"com.google.gcm.noti
 NSString *const kFIRInstanceIDAPNSTokenNotification = @"com.firebase.iid.notif.apns-token";
 NSString *const kFIRInstanceIDDefaultGCMTokenFailNotification =
     @"com.firebase.iid.notif.fcm-token-fail";
-
+NSString *const kFIRInstanceIDMessagingUpdateTokenNotification =
+    @"com.firebase.messaging.notif.fcm-token-refreshed";
 NSString *const kFIRInstanceIDIdentityInvalidatedNotification = @"com.google.iid.identity-invalid";
 
 // Miscellaneous

+ 5 - 0
Firebase/InstanceID/FIRInstanceIDStore.h

@@ -85,6 +85,11 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)saveTokenInfo:(FIRInstanceIDTokenInfo *)tokenInfo handler:(void (^)(NSError *))handler;
 
+/*
+ * Save instanceID token info to cache only.
+ */
+- (void)saveTokenInfoInCacheOnly:(FIRInstanceIDTokenInfo *)tokenInfo;
+
 #pragma mark - Get
 
 /**

+ 4 - 0
Firebase/InstanceID/FIRInstanceIDStore.m

@@ -202,6 +202,10 @@ static NSString *const kFIRInstanceIDLibraryVersion = @"GMSInstanceID-version";
   [self.tokenStore saveTokenInfo:tokenInfo handler:handler];
 }
 
+- (void)saveTokenInfoInCacheOnly:(FIRInstanceIDTokenInfo *)tokenInfo {
+  [self.tokenStore saveTokenInfoInCacheOnly:tokenInfo];
+}
+
 #pragma mark - Delete
 
 - (void)removeCachedTokenWithAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {

+ 9 - 0
Firebase/InstanceID/FIRInstanceIDTokenManager.h

@@ -146,4 +146,13 @@ typedef NS_OPTIONS(NSUInteger, FIRInstanceIDInvalidTokenReason) {
 - (NSArray<FIRInstanceIDTokenInfo *> *)updateTokensToAPNSDeviceToken:(NSData *)deviceToken
                                                            isSandbox:(BOOL)isSandbox;
 
+/*
+ * This method is only called when Messaging SDK is installed and a new token is triggered
+ * by Messaging.
+ * Update default token in cache if the token is updated from a newer versio of Messaging.
+ * This is used when newer version of Messaging SDK will update the token in storage
+ * and notify instanceID to update its own cache as well. No need to write to storage again.
+ */
+- (void)saveDefaultToken:(NSString *)defaultToken withOptions:(NSDictionary *)tokenOptions;
+
 @end

+ 14 - 0
Firebase/InstanceID/FIRInstanceIDTokenManager.m

@@ -27,6 +27,7 @@
 #import "FIRInstanceIDTokenFetchOperation.h"
 #import "FIRInstanceIDTokenInfo.h"
 #import "FIRInstanceIDTokenOperation.h"
+#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
 #import "NSError+FIRInstanceID.h"
 
 @interface FIRInstanceIDTokenManager () <FIRInstanceIDStoreDelegate>
@@ -337,4 +338,17 @@
   return tokenInfosToDelete;
 }
 
+- (void)saveDefaultToken:(NSString *)defaultToken withOptions:(NSDictionary *)tokenOptions {
+  FIROptions *options = FIRApp.defaultApp.options;
+  FIRInstanceIDTokenInfo *tokenInfo =
+      [[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:options.GCMSenderID
+                                                         scope:@"*"
+                                                         token:defaultToken
+                                                    appVersion:FIRInstanceIDCurrentAppVersion()
+                                                 firebaseAppID:options.googleAppID];
+  tokenInfo.APNSInfo = [[FIRInstanceIDAPNSInfo alloc] initWithTokenOptionsDictionary:tokenOptions];
+
+  [self.instanceIDStore saveTokenInfoInCacheOnly:tokenInfo];
+}
+
 @end

+ 5 - 0
Firebase/InstanceID/FIRInstanceIDTokenStore.h

@@ -82,6 +82,11 @@ NS_ASSUME_NONNULL_BEGIN
 - (void)saveTokenInfo:(FIRInstanceIDTokenInfo *)tokenInfo
               handler:(nullable void (^)(NSError *))handler;
 
+/*
+ * Save the instanceID token info to the cache only.
+ */
+- (void)saveTokenInfoInCacheOnly:(FIRInstanceIDTokenInfo *)tokenInfo;
+
 #pragma mark - Delete
 
 /**

+ 14 - 0
Firebase/InstanceID/FIRInstanceIDTokenStore.m

@@ -124,6 +124,20 @@ static NSString *const kFIRInstanceIDTokenKeychainId = @"com.google.iid-tokens";
   [self.keychain setData:tokenInfoData forService:service account:account handler:handler];
 }
 
+- (void)saveTokenInfoInCacheOnly:(FIRInstanceIDTokenInfo *)tokenInfo {
+  tokenInfo.cacheTime = [NSDate date];
+  // Always write to the Keychain, so that the cacheTime is up-to-date.
+  NSData *tokenInfoData;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo];
+#pragma clang diagnostic pop
+  NSString *account = FIRInstanceIDAppIdentifier();
+  NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntity
+                                                            scope:tokenInfo.scope];
+  [self.keychain setDataInCache:tokenInfoData forService:service account:account];
+}
+
 #pragma mark - Delete
 
 - (void)removeTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity

+ 1 - 1
FirebaseInstanceID.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name             = 'FirebaseInstanceID'
-  s.version          = '4.5.1'
+  s.version          = '4.6.0'
   s.summary          = 'Firebase InstanceID'
 
   s.description      = <<-DESC

+ 2 - 2
FirebaseMessaging.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name             = 'FirebaseMessaging'
-  s.version          = '4.6.1'
+  s.version          = '4.6.2'
   s.summary          = 'Firebase Messaging'
 
   s.description      = <<-DESC
@@ -55,7 +55,7 @@ device, and it is completely free.
   s.osx.framework = 'SystemConfiguration'
   s.weak_framework = 'UserNotifications'
   s.dependency 'FirebaseCore', '~> 6.10'
-  s.dependency 'FirebaseInstanceID', '~> 4.3'
+  s.dependency 'FirebaseInstanceID', '~> 4.6'
   s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 6.7'
   s.dependency 'GoogleUtilities/Reachability', '~> 6.7'
   s.dependency 'GoogleUtilities/Environment', '~> 6.7'

+ 1 - 1
FirebaseMessaging/CHANGELOG.md

@@ -1,4 +1,4 @@
-# unreleased
+# 2020-08 -- v.4.6.2
 - [fixed] Fixed an issue that topic doesn't work in watchOS. (#6160)
 - [fixed] Improved Xcode completion of public API completion handlers in Swift. (#6278)