Эх сурвалжийг харах

Resolve comments

- Add KVO on token properties in GIDGoogleUser. Unit tests for KVO is delayed to avoid adding more OCMock or swizzle.
pinlu 3 жил өмнө
parent
commit
04ecdcdc8c

+ 0 - 1
.gitignore

@@ -5,7 +5,6 @@
 *.pbxuser
 *.mode1v3
 *.mode2v3
-*.pbxproj
 *.perspectivev3
 *.xcuserstate
 *.xcworkspace/

+ 1 - 4
GoogleSignIn/Sources/GIDAuthentication.m

@@ -36,8 +36,6 @@
 #import <AppAuth/OIDTokenResponse.h>
 #endif
 
-NS_ASSUME_NONNULL_BEGIN
-
 // Minimal time interval before expiration for the access token or it needs to be refreshed.
 NSTimeInterval kMinimalTimeToExpire = 60.0;
 
@@ -55,8 +53,7 @@ static NSString *const kOldIOSSystemName = @"iPhone OS";
 // New UIDevice system name for iOS.
 static NSString *const kNewIOSSystemName = @"iOS";
 
-typedef void (^GIDAuthenticationCompletion)(OIDAuthState *_Nullable authState,
-                                            NSError *_Nullable error);
+NS_ASSUME_NONNULL_BEGIN
 
 #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
 

+ 70 - 34
GoogleSignIn/Sources/GIDGoogleUser.m

@@ -103,36 +103,20 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (GIDToken *)accessToken {
   @synchronized(self) {
-    if (!_cachedAccessToken) {
-      _cachedAccessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken
-                                                  expirationDate:_authState.lastTokenResponse.
-                                                                     accessTokenExpirationDate];
-    }
+    return _cachedAccessToken;
   }
-  return _cachedAccessToken;
 }
 
 - (GIDToken *)refreshToken {
   @synchronized(self) {
-    if (!_cachedRefreshToken) {
-      _cachedRefreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken
-                                                   expirationDate:nil];
-    }
+    return _cachedRefreshToken;
   }
-  return _cachedRefreshToken;
 }
 
 - (nullable GIDToken *)idToken {
   @synchronized(self) {
-    NSString *idTokenString = _authState.lastTokenResponse.idToken;
-    if (!_cachedIdToken && idTokenString) {
-      NSDate *idTokenExpirationDate = [[[OIDIDToken alloc]
-                                        initWithIDTokenString:idTokenString] expiresAt];
-      _cachedIdToken = [[GIDToken alloc] initWithTokenString:idTokenString
-                                              expirationDate:idTokenExpirationDate];
-    }
+    return _cachedIdToken;
   }
-  return _cachedIdToken;
 }
 
 - (id<GTMFetcherAuthorizationProtocol>) fetcherAuthorizer {
@@ -143,8 +127,25 @@ NS_ASSUME_NONNULL_BEGIN
                                     NSError *_Nullable error))completion {
   [_authentication doWithFreshTokens:^(OIDAuthState *authState, NSError *error) {
     if (authState) {
-      [self updateAuthState:authState];
-      completion(self, error);
+      NSString *accessTokenString = authState.lastTokenResponse.accessToken;
+      NSDate *accessTokenExpirationDate = authState.lastTokenResponse.accessTokenExpirationDate;
+      NSString *refreshTokenString = authState.refreshToken;
+      NSString *idTokenString = authState.lastTokenResponse.idToken;
+      NSDate *idTokenExpirationDate = [[[OIDIDToken alloc]
+                                        initWithIDTokenString:idTokenString] expiresAt];
+      
+      // Check if it is the current authState.
+      if ([accessTokenString isEqual:self.accessToken.tokenString] &&
+          [self isTheSameExpirationDate:accessTokenExpirationDate
+                                   with:self.accessToken.expirationDate] &&
+          [refreshTokenString isEqual:self.refreshToken.tokenString] &&
+          [idTokenString isEqual:self.idToken.tokenString] &&
+          [self isTheSameExpirationDate:idTokenExpirationDate with:self.idToken.expirationDate]) {
+          completion(self, nil);;
+      } else {
+        [self updateAuthState:authState notifyTokenChanges:YES];
+        completion(self, nil);
+      }
     } else {
       completion(nil, error);
     }
@@ -157,26 +158,51 @@ NS_ASSUME_NONNULL_BEGIN
                       profileData:(nullable GIDProfileData *)profileData {
   self = [super init];
   if (self) {
-    [self updateAuthState:authState profileData:profileData];
+    [self updateAuthState:authState profileData:profileData notifyTokenChanges:NO];
   }
   return self;
 }
 
 - (void)updateAuthState:(OIDAuthState *)authState
-            profileData:(nullable GIDProfileData *)profileData {
+            profileData:(nullable GIDProfileData *)profileData
+     notifyTokenChanges:(BOOL)notify{
   _profile = profileData;
-  [self updateAuthState:authState];
+  [self updateAuthState:authState notifyTokenChanges:notify];
 }
 
-- (void)updateAuthState:(OIDAuthState *)authState {
-    @synchronized(self) {
-      _authState = authState;
-      _authentication = [[GIDAuthentication alloc] initWithAuthState:authState];
-      
-      // These three tokens will be generated in the getter and cached .
-      _cachedAccessToken = nil;
-      _cachedRefreshToken = nil;
-      _cachedIdToken = nil;
+- (void)updateAuthState:(OIDAuthState *)authState
+     notifyTokenChanges:(BOOL)notify{
+  @synchronized(self) {
+    _authState = authState;
+    _authentication = [[GIDAuthentication alloc] initWithAuthState:authState];
+    
+    if (notify) {
+      [self willChangeValueForKey:NSStringFromSelector(@selector(accessToken))];
+      [self willChangeValueForKey:NSStringFromSelector(@selector(idToken))];
+      [self willChangeValueForKey:NSStringFromSelector(@selector(refreshToken))];
+    }
+    
+    // Update three tokens
+    _cachedAccessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken
+                                                expirationDate:_authState.lastTokenResponse.
+                                                                   accessTokenExpirationDate];
+    _cachedRefreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken
+                                                 expirationDate:nil];
+    
+    _cachedIdToken = nil;
+    NSString *idTokenString = _authState.lastTokenResponse.idToken;
+    if (idTokenString) {
+      NSDate *idTokenExpirationDate = [[[OIDIDToken alloc]
+                                        initWithIDTokenString:idTokenString] expiresAt];
+      _cachedIdToken = [[GIDToken alloc] initWithTokenString:idTokenString
+                                              expirationDate:idTokenExpirationDate];
+    }
+    
+    if (notify) {
+      [self didChangeValueForKey:NSStringFromSelector(@selector(accessToken))];
+      [self didChangeValueForKey:NSStringFromSelector(@selector(idToken))];
+      [self didChangeValueForKey:NSStringFromSelector(@selector(refreshToken))];
+    }
   }
 }
 
@@ -193,6 +219,16 @@ NS_ASSUME_NONNULL_BEGIN
   return nil;
 }
 
+// The date is nullable in GIDToken. If they are both nil they are considered equal.
+- (BOOL)isTheSameExpirationDate:(nullable NSDate *)date1
+                           with:(nullable NSDate *)date2 {
+  if (!date1 && !date2) {
+    return YES;
+  }
+  
+  return [date1 isEqualToDate:date2];
+}
+
 #pragma mark - NSSecureCoding
 
 + (BOOL)supportsSecureCoding {
@@ -212,7 +248,7 @@ NS_ASSUME_NONNULL_BEGIN
                                                                 forKey:kAuthenticationKey];
       authState = authentication.authState;
     }
-    [self updateAuthState:authState profileData:profileData];
+    [self updateAuthState:authState profileData:profileData notifyTokenChanges:NO];
   }
   return self;
 }

+ 2 - 1
GoogleSignIn/Sources/GIDGoogleUser_Private.h

@@ -34,7 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 // Update the auth state and profile data.
 - (void)updateAuthState:(OIDAuthState *)authState
-            profileData:(nullable GIDProfileData *)profileData;
+            profileData:(nullable GIDProfileData *)profileData
+     notifyTokenChanges:(BOOL)notify;
 
 @end
 

+ 2 - 1
GoogleSignIn/Sources/GIDSignIn.m

@@ -817,7 +817,8 @@ static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0;
 
       if (self->_currentOptions.addScopesFlow) {
         [self->_currentUser updateAuthState:authState
-                                profileData:handlerAuthFlow.profileData];
+                                profileData:handlerAuthFlow.profileData
+                         notifyTokenChanges:YES];
       } else {
         GIDGoogleUser *user = [[GIDGoogleUser alloc] initWithAuthState:authState
                                                            profileData:handlerAuthFlow.profileData];

+ 1 - 3
GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h

@@ -58,9 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property(nonatomic, readonly, nullable) GIDToken *idToken;
 
 /// Gets a new authorizer for `GTLService`, `GTMSessionFetcher`, or `GTMHTTPFetcher`.
-///
-/// @return A new authorizer
-- (id<GTMFetcherAuthorizationProtocol>) fetcherAuthorizer;
+@property(nonatomic, readonly) id<GTMFetcherAuthorizationProtocol> fetcherAuthorizer;
 
 /// Get a valid access token and a valid ID token, refreshing them first if they have expired or are
 /// about to expire.

+ 2 - 1
GoogleSignIn/Tests/Unit/GIDSignInTest.m

@@ -1356,7 +1356,8 @@ static void *kTestObserverContext = &kTestObserverContext;
   } else {
     if (addScopesFlow) {
       [[_user expect] updateAuthState:SAVE_TO_ARG_BLOCK(authState)
-                          profileData:SAVE_TO_ARG_BLOCK(profileData)];
+                          profileData:SAVE_TO_ARG_BLOCK(profileData)
+                   notifyTokenChanges:YES];
     } else {
       [[[_user stub] andReturn:_user] alloc];
       (void)[[[_user expect] andReturn:_user] initWithAuthState:SAVE_TO_ARG_BLOCK(authState)