Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 105 additions & 5 deletions Example/InstanceID/Tests/FIRInstanceIDTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ @interface FIRInstanceID (ExposedForTest)
@property(nonatomic, readwrite, strong) FIRInstallations *installations;
@property(nonatomic, readwrite, copy) NSString *fcmSenderID;
@property(nonatomic, readwrite, copy) NSString *firebaseAppID;
@property(nonatomic, readwrite, copy) NSString *defaultFCMToken;

- (NSInteger)retryIntervalToFetchDefaultToken;
- (BOOL)isFCMAutoInitEnabled;
Expand Down Expand Up @@ -651,7 +652,6 @@ - (void)testDefaultToken_callbackInvokedForUnchangedToken {
return obj != nil;
}]];

__block NSInteger notificationPostCount = 0;
__block NSString *notificationToken = nil;

// Fetch token once to store token state
Expand All @@ -663,8 +663,6 @@ - (void)testDefaultToken_callbackInvokedForUnchangedToken {
usingBlock:^(NSNotification *_Nonnull note) {
// Should have saved token to cache
cachedTokenInfo = sTokenInfo;

notificationPostCount++;
notificationToken = [[self.instanceID token] copy];
[defaultTokenExpectation fulfill];
}];
Expand Down Expand Up @@ -721,7 +719,6 @@ - (void)testDefaultTokenFetch_returnValidToken {
return obj != nil;
}]];

__block int notificationPostCount = 0;
__block NSString *notificationToken = nil;

NSString *notificationName = kFIRInstanceIDTokenRefreshNotification;
Expand All @@ -733,7 +730,6 @@ - (void)testDefaultTokenFetch_returnValidToken {
// Should have saved token to cache
cachedTokenInfo = sTokenInfo;

notificationPostCount++;
notificationToken = [[self.instanceID token] copy];
[defaultTokenExpectation fulfill];
}];
Expand Down Expand Up @@ -800,6 +796,7 @@ - (void)testDefaultTokenFetch_retryFetchToken {
__block NSString *notificationToken = nil;

NSString *notificationName = kFIRInstanceIDTokenRefreshNotification;

self.tokenRefreshNotificationObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:notificationName
object:nil
Expand Down Expand Up @@ -1328,6 +1325,109 @@ - (void)testInstanceIDDelete_keyChainError {
OCMVerifyAll(self.mockTokenManager);
}

- (void)testRefreshDifferentTokenFromMessaging {
_instanceID.defaultFCMToken = kToken;
XCTAssertEqualObjects(_instanceID.defaultFCMToken, kToken);
NSString *newTokenFromMessaging = @"a_new_token_from_messaging";
FIRInstanceIDTokenInfo *cachedTokenInfo =
[[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope
token:kToken
appVersion:@""
firebaseAppID:kGoogleAppID];
OCMStub([self.mockTokenManager
cachedTokenInfoWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope])
.andReturn(cachedTokenInfo);

OCMExpect([self.mockTokenManager saveDefaultToken:newTokenFromMessaging
withOptions:[OCMArg any]]);
[[NSNotificationCenter defaultCenter]
postNotificationName:kFIRInstanceIDMessagingUpdateTokenNotification
object:newTokenFromMessaging];
OCMVerifyAll(self.mockTokenManager);
XCTAssertEqualObjects(_instanceID.defaultFCMToken, newTokenFromMessaging);
}

- (void)testRefreshTheSameTokenFromMessaging {
_instanceID.defaultFCMToken = kToken;
XCTAssertEqualObjects(_instanceID.defaultFCMToken, kToken);

NSString *newTokenFromMessaging = kToken;
FIRInstanceIDTokenInfo *cachedTokenInfo =
[[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope
token:kToken
appVersion:@""
firebaseAppID:kGoogleAppID];
OCMStub([self.mockTokenManager
cachedTokenInfoWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope])
.andReturn(cachedTokenInfo);

OCMReject([self.mockTokenManager saveDefaultToken:newTokenFromMessaging
withOptions:[OCMArg any]]);
[[NSNotificationCenter defaultCenter]
postNotificationName:kFIRInstanceIDMessagingUpdateTokenNotification
object:newTokenFromMessaging];
OCMVerifyAll(self.mockTokenManager);
XCTAssertEqualObjects(_instanceID.defaultFCMToken, newTokenFromMessaging);
}

- (void)testRefreshDifferentTokenInInstanceIDStorage {
_instanceID.defaultFCMToken = kToken;
XCTAssertEqualObjects(_instanceID.defaultFCMToken, kToken);
// New token from messaging is the same as local cache in InstanceID
// But the token in InstanceID storage is different
NSString *newTokenFromMessaging = kToken;

FIRInstanceIDTokenInfo *cachedTokenInfo =
[[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope
token:@"a_outdated_token_in_storage"
appVersion:@""
firebaseAppID:kGoogleAppID];
OCMStub([self.mockTokenManager
cachedTokenInfoWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope])
.andReturn(cachedTokenInfo);

OCMExpect([self.mockTokenManager saveDefaultToken:newTokenFromMessaging
withOptions:[OCMArg any]]);
[[NSNotificationCenter defaultCenter]
postNotificationName:kFIRInstanceIDMessagingUpdateTokenNotification
object:newTokenFromMessaging];
OCMVerifyAll(self.mockTokenManager);
XCTAssertEqualObjects(_instanceID.defaultFCMToken, newTokenFromMessaging);
}

- (void)testRefreshNullTokenFromMessaging {
_instanceID.defaultFCMToken = kToken;
XCTAssertEqualObjects(_instanceID.defaultFCMToken, kToken);
// New token from messaging is the same as local cache in InstanceID
// But the token in InstanceID storage is different
NSString *newTokenFromMessaging = nil;

FIRInstanceIDTokenInfo *cachedTokenInfo =
[[FIRInstanceIDTokenInfo alloc] initWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope
token:kToken
appVersion:@""
firebaseAppID:kGoogleAppID];
OCMStub([self.mockTokenManager
cachedTokenInfoWithAuthorizedEntity:kAuthorizedEntity
scope:kFIRInstanceIDDefaultTokenScope])
.andReturn(cachedTokenInfo);

OCMExpect([self.mockTokenManager saveDefaultToken:newTokenFromMessaging
withOptions:[OCMArg any]]);
[[NSNotificationCenter defaultCenter]
postNotificationName:kFIRInstanceIDMessagingUpdateTokenNotification
object:newTokenFromMessaging];
OCMVerifyAll(self.mockTokenManager);
XCTAssertEqualObjects(_instanceID.defaultFCMToken, newTokenFromMessaging);
}

#pragma mark - Private Helpers

- (void)stubInstallationsToReturnValidID {
Expand Down
5 changes: 4 additions & 1 deletion Firebase/InstanceID/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Unreleased -- 7.0.0
# Unreleased
- [changed] Added a check on whether the default token has been changed from Messaging before writing to storage. (#7223)

# 2020-10 -- 7.0.0
- [changed] Deprecated private `-[FIRInstanceID appInstanceID:]` method was removed. (#4486)
- [fixed] Fixed an issue that APNS token is not sent in token request when there's a delay of getting the APNS token from Apple. (#6553)

Expand Down
19 changes: 16 additions & 3 deletions Firebase/InstanceID/FIRInstanceID.m
Original file line number Diff line number Diff line change
Expand Up @@ -1127,9 +1127,22 @@ - (void)observeFirebaseMessagingTokenChanges {
- (void)messagingTokenDidChangeNotificationReceived:(NSNotification *)notification {
NSString *tokenUpdatedFromMessaging = notification.object;
if (!tokenUpdatedFromMessaging || [tokenUpdatedFromMessaging isKindOfClass:[NSString class]]) {
self.defaultFCMToken = tokenUpdatedFromMessaging;
[self.tokenManager saveDefaultToken:tokenUpdatedFromMessaging
withOptions:[self defaultTokenOptions]];
// Check the token from storage along with local value.
FIRInstanceIDTokenInfo *cachedTokenInfo =
[self.tokenManager cachedTokenInfoWithAuthorizedEntity:self.fcmSenderID
scope:kFIRInstanceIDDefaultTokenScope];
NSString *cachedToken = cachedTokenInfo.token;

if (self.defaultFCMToken.length != tokenUpdatedFromMessaging.length ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the length checks needed? Aren't two isEqualToString checks sufficient?

Copy link
Contributor Author

@charlotteliang charlotteliang Dec 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case both are null, then [null isEqualtoString: null] return false, even though it should be true.

cachedToken.length != tokenUpdatedFromMessaging.length ||
(self.defaultFCMToken.length && tokenUpdatedFromMessaging.length &&
![self.defaultFCMToken isEqualToString:tokenUpdatedFromMessaging]) ||
(cachedToken.length && tokenUpdatedFromMessaging.length &&
![cachedToken isEqualToString:tokenUpdatedFromMessaging])) {
self.defaultFCMToken = tokenUpdatedFromMessaging;
[self.tokenManager saveDefaultToken:tokenUpdatedFromMessaging
withOptions:[self defaultTokenOptions]];
}
}
}

Expand Down
1 change: 1 addition & 0 deletions FirebaseMessaging/Apps/Shared/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct ContentView: View {
// simulator renders a single truncated line even though the Preview renders it
// appropriately. Potentially a bug in the simulator?
.layoutPriority(1)
.lineLimit(7)
}
NavigationLink(destination: SettingsView()) {
Text("Settings")
Expand Down
3 changes: 3 additions & 0 deletions FirebaseMessaging/Apps/Shared/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, MessagingDelegate {

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
identity.token = fcmToken
print("=============================\n")
print("Did refresh token:\n", identity.token ?? "")
print("\n=============================\n")
}
}