[google_sign_in] Upgrade to GoogleSignIn 6.2, support arm64 simulators (#5708)

diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md
index 9edadf7..86a3b56 100644
--- a/packages/google_sign_in/google_sign_in/CHANGELOG.md
+++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 * Updates tests to use a mock platform instead of relying on default
   method channel implementation internals.
+* Removes example workaround to build for arm64 iOS simulators.
 
 ## 5.3.1
 
diff --git a/packages/google_sign_in/google_sign_in/example/ios/Podfile b/packages/google_sign_in/google_sign_in/example/ios/Podfile
index 56085c3..f7d6a5e 100644
--- a/packages/google_sign_in/google_sign_in/example/ios/Podfile
+++ b/packages/google_sign_in/google_sign_in/example/ios/Podfile
@@ -34,9 +34,5 @@
 post_install do |installer|
   installer.pods_project.targets.each do |target|
     flutter_additional_ios_build_settings(target)
-    target.build_configurations.each do |build_configuration|
-      # GoogleSignIn does not support arm64 simulators.
-      build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
-    end
   end
 end
diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
index 8909bb9..6c698e1 100644
--- a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj
@@ -426,7 +426,6 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ENABLE_BITCODE = NO;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
@@ -448,7 +447,6 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ENABLE_BITCODE = NO;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md
index 90069d0..e5de49d 100644
--- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md
+++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 5.3.0
+
+* Supports arm64 iOS simulators by increasing GoogleSignIn dependency to version 6.2.
+
 ## 5.2.7
 
 * Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors
diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/Podfile b/packages/google_sign_in/google_sign_in_ios/example/ios/Podfile
index b20e1ad..6c315d2 100644
--- a/packages/google_sign_in/google_sign_in_ios/example/ios/Podfile
+++ b/packages/google_sign_in/google_sign_in_ios/example/ios/Podfile
@@ -42,9 +42,5 @@
 post_install do |installer|
   installer.pods_project.targets.each do |target|
     flutter_additional_ios_build_settings(target)
-    target.build_configurations.each do |build_configuration|
-      # GoogleSignIn does not support arm64 simulators.
-      build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
-    end
   end
 end
diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj
index f2bf4eb..a7f2019 100644
--- a/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj
@@ -384,7 +384,7 @@
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
-				"${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
+				"${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
@@ -603,7 +603,6 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ENABLE_BITCODE = NO;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
@@ -625,7 +624,6 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ENABLE_BITCODE = NO;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
@@ -647,7 +645,6 @@
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CODE_SIGN_STYLE = Automatic;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				INFOPLIST_FILE = RunnerTests/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests;
@@ -662,7 +659,6 @@
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CODE_SIGN_STYLE = Automatic;
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				INFOPLIST_FILE = RunnerTests/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests;
diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m b/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m
index 3bc08d1..7efd490 100644
--- a/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m
+++ b/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m
@@ -64,66 +64,103 @@
 }
 
 - (void)testDisconnect {
+  [[self.mockSignIn stub] disconnectWithCallback:[OCMArg invokeBlockWithArgs:[NSNull null], nil]];
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"disconnect"
                                                                     arguments:nil];
 
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
   [self.plugin handleMethodCall:methodCall
-                         result:^(id result){
+                         result:^(NSDictionary *result) {
+                           XCTAssertEqualObjects(result, @{});
+                           [expectation fulfill];
                          }];
-  OCMVerify([self.mockSignIn disconnect]);
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testDisconnectIgnoresError {
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeHasNoAuthInKeychain
+                                   userInfo:nil];
+  [[self.mockSignIn stub] disconnectWithCallback:[OCMArg invokeBlockWithArgs:error, nil]];
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"disconnect"
+                                                                    arguments:nil];
+
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:methodCall
+                         result:^(NSDictionary *result) {
+                           XCTAssertEqualObjects(result, @{});
+                           [expectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
 #pragma mark - Init
 
 - (void)testInitGoogleServiceInfoPlist {
-  FlutterMethodCall *methodCall = [FlutterMethodCall
-      methodCallWithMethodName:@"init"
-                     arguments:@{@"scopes" : @[ @"mockScope1" ], @"hostedDomain" : @"example.com"}];
+  FlutterMethodCall *initMethodCall =
+      [FlutterMethodCall methodCallWithMethodName:@"init"
+                                        arguments:@{@"hostedDomain" : @"example.com"}];
 
-  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
-  [self.plugin handleMethodCall:methodCall
+  XCTestExpectation *initExpectation =
+      [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:initMethodCall
                          result:^(id result) {
                            XCTAssertNil(result);
-                           [expectation fulfill];
+                           [initExpectation fulfill];
                          }];
   [self waitForExpectationsWithTimeout:5.0 handler:nil];
 
-  id mockSignIn = self.mockSignIn;
-  OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]);
-  OCMVerify([mockSignIn setHostedDomain:@"example.com"]);
-
-  // Set in example app GoogleService-Info.plist.
-  OCMVerify([mockSignIn
-      setClientID:@"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"]);
-  OCMVerify([mockSignIn setServerClientID:@"YOUR_SERVER_CLIENT_ID"]);
+  // Initialization values used in the next sign in request.
+  FlutterMethodCall *signInMethodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+                                                                          arguments:nil];
+  [self.plugin handleMethodCall:signInMethodCall
+                         result:^(id r){
+                         }];
+  OCMVerify([self.mockSignIn
+       signInWithConfiguration:[OCMArg checkWithBlock:^BOOL(GIDConfiguration *configuration) {
+         // Set in example app GoogleService-Info.plist.
+         return
+             [configuration.hostedDomain isEqualToString:@"example.com"] &&
+             [configuration.clientID
+                 isEqualToString:
+                     @"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"] &&
+             [configuration.serverClientID isEqualToString:@"YOUR_SERVER_CLIENT_ID"];
+       }]
+      presentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]
+                          hint:nil
+              additionalScopes:OCMOCK_ANY
+                      callback:OCMOCK_ANY]);
 }
 
-- (void)testInitNullDomain {
-  FlutterMethodCall *methodCall =
-      [FlutterMethodCall methodCallWithMethodName:@"init"
-                                        arguments:@{@"hostedDomain" : [NSNull null]}];
+- (void)testInitDynamicClientIdNullDomain {
+  FlutterMethodCall *initMethodCall = [FlutterMethodCall
+      methodCallWithMethodName:@"init"
+                     arguments:@{@"hostedDomain" : [NSNull null], @"clientId" : @"mockClientId"}];
 
-  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
-  [self.plugin handleMethodCall:methodCall
-                         result:^(id r) {
-                           [expectation fulfill];
+  XCTestExpectation *initExpectation =
+      [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:initMethodCall
+                         result:^(id result) {
+                           XCTAssertNil(result);
+                           [initExpectation fulfill];
                          }];
   [self waitForExpectationsWithTimeout:5.0 handler:nil];
-  OCMVerify([self.mockSignIn setHostedDomain:nil]);
-}
 
-- (void)testInitDynamicClientId {
-  FlutterMethodCall *methodCall =
-      [FlutterMethodCall methodCallWithMethodName:@"init"
-                                        arguments:@{@"clientId" : @"mockClientId"}];
-
-  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
-  [self.plugin handleMethodCall:methodCall
-                         result:^(id r) {
-                           [expectation fulfill];
+  // Initialization values used in the next sign in request.
+  FlutterMethodCall *signInMethodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+                                                                          arguments:nil];
+  [self.plugin handleMethodCall:signInMethodCall
+                         result:^(id r){
                          }];
-  [self waitForExpectationsWithTimeout:5.0 handler:nil];
-  OCMVerify([self.mockSignIn setClientID:@"mockClientId"]);
+  OCMVerify([self.mockSignIn
+       signInWithConfiguration:[OCMArg checkWithBlock:^BOOL(GIDConfiguration *configuration) {
+         return configuration.hostedDomain == nil &&
+                [configuration.clientID isEqualToString:@"mockClientId"];
+       }]
+      presentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]
+                          hint:nil
+              additionalScopes:OCMOCK_ANY
+                      callback:OCMOCK_ANY]);
 }
 
 #pragma mark - Is signed in
@@ -161,59 +198,195 @@
 #pragma mark - Sign in silently
 
 - (void)testSignInSilently {
-  OCMExpect([self.mockSignIn restorePreviousSignIn]);
+  id mockUser = OCMClassMock([GIDGoogleUser class]);
+  OCMStub([mockUser userID]).andReturn(@"mockID");
 
-  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently"
-                                                                    arguments:nil];
+  [[self.mockSignIn stub]
+      restorePreviousSignInWithCallback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
 
-  [self.plugin handleMethodCall:methodCall
-                         result:^(id result){
-                         }];
-  OCMVerifyAll(self.mockSignIn);
-}
-
-- (void)testSignInSilentlyFailsConcurrently {
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently"
                                                                     arguments:nil];
 
   XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
-
-  OCMExpect([self.mockSignIn restorePreviousSignIn]).andDo(^(NSInvocation *invocation) {
-    // Simulate calling the same method while the previous one is in flight.
-    [self.plugin handleMethodCall:methodCall
-                           result:^(FlutterError *result) {
-                             XCTAssertEqualObjects(result.code, @"concurrent-requests");
-                             [expectation fulfill];
-                           }];
-  });
-
   [self.plugin handleMethodCall:methodCall
-                         result:^(id result){
+                         result:^(NSDictionary<NSString *, NSString *> *result) {
+                           XCTAssertEqualObjects(result[@"displayName"], [NSNull null]);
+                           XCTAssertEqualObjects(result[@"email"], [NSNull null]);
+                           XCTAssertEqualObjects(result[@"id"], @"mockID");
+                           XCTAssertEqualObjects(result[@"photoUrl"], [NSNull null]);
+                           XCTAssertEqualObjects(result[@"serverAuthCode"], [NSNull null]);
+                           [expectation fulfill];
                          }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
 
+- (void)testSignInSilentlyWithError {
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeHasNoAuthInKeychain
+                                   userInfo:nil];
+
+  [[self.mockSignIn stub]
+      restorePreviousSignInWithCallback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently"
+                                                                    arguments:nil];
+
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:methodCall
+                         result:^(FlutterError *result) {
+                           XCTAssertEqualObjects(result.code, @"sign_in_required");
+                           [expectation fulfill];
+                         }];
   [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
 #pragma mark - Sign in
 
 - (void)testSignIn {
+  id mockUser = OCMClassMock([GIDGoogleUser class]);
+  id mockUserProfile = OCMClassMock([GIDProfileData class]);
+  OCMStub([mockUserProfile name]).andReturn(@"mockDisplay");
+  OCMStub([mockUserProfile email]).andReturn(@"mock@example.com");
+  OCMStub([mockUserProfile hasImage]).andReturn(YES);
+  OCMStub([mockUserProfile imageURLWithDimension:1337])
+      .andReturn([NSURL URLWithString:@"https://example.com/profile.png"]);
+
+  OCMStub([mockUser profile]).andReturn(mockUserProfile);
+  OCMStub([mockUser userID]).andReturn(@"mockID");
+  OCMStub([mockUser serverAuthCode]).andReturn(@"mockAuthCode");
+
+  [[self.mockSignIn expect]
+       signInWithConfiguration:[OCMArg checkWithBlock:^BOOL(GIDConfiguration *configuration) {
+         return [configuration.clientID
+             isEqualToString:
+                 @"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"];
+       }]
+      presentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]
+                          hint:nil
+              additionalScopes:@[]
+                      callback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
+
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
                                                                     arguments:nil];
 
-  [self.plugin handleMethodCall:methodCall
-                         result:^(NSNumber *result){
-                         }];
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin
+      handleMethodCall:methodCall
+                result:^(NSDictionary<NSString *, NSString *> *result) {
+                  XCTAssertEqualObjects(result[@"displayName"], @"mockDisplay");
+                  XCTAssertEqualObjects(result[@"email"], @"mock@example.com");
+                  XCTAssertEqualObjects(result[@"id"], @"mockID");
+                  XCTAssertEqualObjects(result[@"photoUrl"], @"https://example.com/profile.png");
+                  XCTAssertEqualObjects(result[@"serverAuthCode"], @"mockAuthCode");
+                  [expectation fulfill];
+                }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
 
-  id mockSignIn = self.mockSignIn;
-  OCMVerify([mockSignIn
-      setPresentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]]);
-  OCMVerify([mockSignIn signIn]);
+  OCMVerifyAll(self.mockSignIn);
 }
 
-- (void)testSignInExecption {
+- (void)testSignInWithInitializedScopes {
+  FlutterMethodCall *initMethodCall =
+      [FlutterMethodCall methodCallWithMethodName:@"init"
+                                        arguments:@{@"scopes" : @[ @"initial1", @"initial2" ]}];
+
+  XCTestExpectation *initExpectation =
+      [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:initMethodCall
+                         result:^(id result) {
+                           XCTAssertNil(result);
+                           [initExpectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+
+  id mockUser = OCMClassMock([GIDGoogleUser class]);
+  OCMStub([mockUser userID]).andReturn(@"mockID");
+
+  [[self.mockSignIn expect]
+       signInWithConfiguration:OCMOCK_ANY
+      presentingViewController:OCMOCK_ANY
+                          hint:nil
+              additionalScopes:[OCMArg checkWithBlock:^BOOL(NSArray<NSString *> *scopes) {
+                return [[NSSet setWithArray:scopes]
+                    isEqualToSet:[NSSet setWithObjects:@"initial1", @"initial2", nil]];
+              }]
+                      callback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
+
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
                                                                     arguments:nil];
-  OCMExpect([self.mockSignIn signIn])
+
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:methodCall
+                         result:^(NSDictionary<NSString *, NSString *> *result) {
+                           XCTAssertEqualObjects(result[@"id"], @"mockID");
+                           [expectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+
+  OCMVerifyAll(self.mockSignIn);
+}
+
+- (void)testSignInAlreadyGranted {
+  id mockUser = OCMClassMock([GIDGoogleUser class]);
+  OCMStub([mockUser userID]).andReturn(@"mockID");
+
+  [[self.mockSignIn stub]
+       signInWithConfiguration:OCMOCK_ANY
+      presentingViewController:OCMOCK_ANY
+                          hint:nil
+              additionalScopes:OCMOCK_ANY
+                      callback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
+
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeScopesAlreadyGranted
+                                   userInfo:nil];
+  [[self.mockSignIn stub] addScopes:OCMOCK_ANY
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+                                                                    arguments:nil];
+
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:methodCall
+                         result:^(NSDictionary<NSString *, NSString *> *result) {
+                           XCTAssertEqualObjects(result[@"id"], @"mockID");
+                           [expectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testSignInError {
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeCanceled
+                                   userInfo:nil];
+  [[self.mockSignIn stub]
+       signInWithConfiguration:OCMOCK_ANY
+      presentingViewController:OCMOCK_ANY
+                          hint:nil
+              additionalScopes:OCMOCK_ANY
+                      callback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+                                                                    arguments:nil];
+
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:methodCall
+                         result:^(FlutterError *result) {
+                           XCTAssertEqualObjects(result.code, @"sign_in_canceled");
+                           [expectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+- (void)testSignInException {
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn"
+                                                                    arguments:nil];
+  OCMExpect([self.mockSignIn signInWithConfiguration:OCMOCK_ANY
+                            presentingViewController:OCMOCK_ANY
+                                                hint:OCMOCK_ANY
+                                    additionalScopes:OCMOCK_ANY
+                                            callback:OCMOCK_ANY])
       .andThrow([NSException exceptionWithName:@"MockName" reason:@"MockReason" userInfo:nil]);
 
   __block FlutterError *error;
@@ -237,7 +410,7 @@
   OCMStub([mockAuthentication idToken]).andReturn(@"mockIdToken");
   OCMStub([mockAuthentication accessToken]).andReturn(@"mockAccessToken");
   [[mockAuthentication stub]
-      getTokensWithHandler:[OCMArg invokeBlockWithArgs:mockAuthentication, [NSNull null], nil]];
+      doWithFreshTokens:[OCMArg invokeBlockWithArgs:mockAuthentication, [NSNull null], nil]];
   OCMStub([mockUser authentication]).andReturn(mockAuthentication);
 
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
@@ -262,7 +435,7 @@
                                        code:kGIDSignInErrorCodeHasNoAuthInKeychain
                                    userInfo:nil];
   [[mockAuthentication stub]
-      getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+      doWithFreshTokens:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
   OCMStub([mockUser authentication]).andReturn(mockAuthentication);
 
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
@@ -287,7 +460,7 @@
                                        code:kGIDSignInErrorCodeCanceled
                                    userInfo:nil];
   [[mockAuthentication stub]
-      getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+      doWithFreshTokens:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
   OCMStub([mockUser authentication]).andReturn(mockAuthentication);
 
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
@@ -310,7 +483,7 @@
   id mockAuthentication = OCMClassMock([GIDAuthentication class]);
   NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:nil];
   [[mockAuthentication stub]
-      getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+      doWithFreshTokens:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
   OCMStub([mockUser authentication]).andReturn(mockAuthentication);
 
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
@@ -333,7 +506,7 @@
   id mockAuthentication = OCMClassMock([GIDAuthentication class]);
   NSError *error = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil];
   [[mockAuthentication stub]
-      getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+      doWithFreshTokens:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
   OCMStub([mockUser authentication]).andReturn(mockAuthentication);
 
   FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens"
@@ -352,7 +525,12 @@
 #pragma mark - Request scopes
 
 - (void)testRequestScopesResultErrorIfNotSignedIn {
-  OCMStub([self.mockSignIn currentUser]).andReturn(nil);
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeNoCurrentUser
+                                   userInfo:nil];
+  [[self.mockSignIn stub] addScopes:@[ @"mockScope1" ]
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
 
   FlutterMethodCall *methodCall =
       [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
@@ -368,14 +546,16 @@
 }
 
 - (void)testRequestScopesIfNoMissingScope {
-  // Mock Google Signin internal calls
-  GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
-  OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
-  NSArray *requestedScopes = @[ @"mockScope1" ];
-  OCMStub(mockUser.grantedScopes).andReturn(requestedScopes);
+  NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain
+                                       code:kGIDSignInErrorCodeScopesAlreadyGranted
+                                   userInfo:nil];
+  [[self.mockSignIn stub] addScopes:@[ @"mockScope1" ]
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
+
   FlutterMethodCall *methodCall =
       [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
-                                        arguments:@{@"scopes" : requestedScopes}];
+                                        arguments:@{@"scopes" : @[ @"mockScope1" ]}];
 
   XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
   [self.plugin handleMethodCall:methodCall
@@ -386,39 +566,50 @@
   [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
-- (void)testRequestScopesRequestsIfNotGranted {
-  // Mock Google Signin internal calls
-  GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
-  OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
-  NSArray *requestedScopes = @[ @"mockScope1" ];
-  OCMStub(mockUser.grantedScopes).andReturn(@[]);
-  id mockSignIn = self.mockSignIn;
-  OCMStub([mockSignIn scopes]).andReturn(@[]);
+- (void)testRequestScopesWithUnknownError {
+  NSError *error = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil];
+  [[self.mockSignIn stub] addScopes:@[ @"mockScope1" ]
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]];
 
   FlutterMethodCall *methodCall =
       [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
-                                        arguments:@{@"scopes" : requestedScopes}];
+                                        arguments:@{@"scopes" : @[ @"mockScope1" ]}];
 
+  XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"];
   [self.plugin handleMethodCall:methodCall
-                         result:^(id r){
+                         result:^(NSNumber *result) {
+                           XCTAssertFalse(result.boolValue);
+                           [expectation fulfill];
                          }];
-
-  OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]);
-  OCMVerify([mockSignIn signIn]);
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
-- (void)testRequestScopesReturnsFalseIfNotGranted {
-  // Mock Google Signin internal calls
+- (void)testRequestScopesException {
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
+                                                                    arguments:nil];
+  OCMExpect([self.mockSignIn addScopes:@[] presentingViewController:OCMOCK_ANY callback:OCMOCK_ANY])
+      .andThrow([NSException exceptionWithName:@"MockName" reason:@"MockReason" userInfo:nil]);
+
+  [self.plugin handleMethodCall:methodCall
+                         result:^(FlutterError *result) {
+                           XCTAssertEqualObjects(result.code, @"request_scopes");
+                           XCTAssertEqualObjects(result.message, @"MockReason");
+                           XCTAssertEqualObjects(result.details, @"MockName");
+                         }];
+}
+
+- (void)testRequestScopesReturnsFalseIfOnlySubsetGranted {
   GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
   OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
-  NSArray *requestedScopes = @[ @"mockScope1" ];
-  OCMStub(mockUser.grantedScopes).andReturn(@[]);
+  NSArray<NSString *> *requestedScopes = @[ @"mockScope1", @"mockScope2" ];
 
-  OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) {
-    [((NSObject<GIDSignInDelegate> *)self.plugin) signIn:self.mockSignIn
-                                        didSignInForUser:mockUser
-                                               withError:nil];
-  });
+  // Only grant one of the two requested scopes.
+  OCMStub(mockUser.grantedScopes).andReturn(@[ @"mockScope1" ]);
+
+  [[self.mockSignIn stub] addScopes:requestedScopes
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
 
   FlutterMethodCall *methodCall =
       [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
@@ -433,20 +624,53 @@
   [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
+- (void)testRequestsInitializedScopes {
+  FlutterMethodCall *initMethodCall =
+      [FlutterMethodCall methodCallWithMethodName:@"init"
+                                        arguments:@{@"scopes" : @[ @"initial1", @"initial2" ]}];
+
+  XCTestExpectation *initExpectation =
+      [self expectationWithDescription:@"expect result returns true"];
+  [self.plugin handleMethodCall:initMethodCall
+                         result:^(id result) {
+                           XCTAssertNil(result);
+                           [initExpectation fulfill];
+                         }];
+  [self waitForExpectationsWithTimeout:5.0 handler:nil];
+
+  // Include one of the initially requested scopes.
+  NSArray<NSString *> *addedScopes = @[ @"initial1", @"addScope1", @"addScope2" ];
+
+  FlutterMethodCall *methodCall =
+      [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
+                                        arguments:@{@"scopes" : addedScopes}];
+
+  [self.plugin handleMethodCall:methodCall
+                         result:^(id result){
+                         }];
+
+  // All four scopes are requested.
+  [[self.mockSignIn verify]
+                     addScopes:[OCMArg checkWithBlock:^BOOL(NSArray<NSString *> *scopes) {
+                       return [[NSSet setWithArray:scopes]
+                           isEqualToSet:[NSSet setWithObjects:@"initial1", @"initial2",
+                                                              @"addScope1", @"addScope2", nil]];
+                     }]
+      presentingViewController:OCMOCK_ANY
+                      callback:OCMOCK_ANY];
+}
+
 - (void)testRequestScopesReturnsTrueIfGranted {
-  // Mock Google Signin internal calls
   GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]);
   OCMStub([self.mockSignIn currentUser]).andReturn(mockUser);
-  NSArray *requestedScopes = @[ @"mockScope1" ];
-  NSMutableArray *availableScopes = [NSMutableArray new];
-  OCMStub(mockUser.grantedScopes).andReturn(availableScopes);
+  NSArray<NSString *> *requestedScopes = @[ @"mockScope1", @"mockScope2" ];
 
-  OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) {
-    [availableScopes addObject:@"mockScope1"];
-    [((NSObject<GIDSignInDelegate> *)self.plugin) signIn:self.mockSignIn
-                                        didSignInForUser:mockUser
-                                               withError:nil];
-  });
+  // Grant both of the requested scopes.
+  OCMStub(mockUser.grantedScopes).andReturn(requestedScopes);
+
+  [[self.mockSignIn stub] addScopes:requestedScopes
+           presentingViewController:OCMOCK_ANY
+                           callback:[OCMArg invokeBlockWithArgs:mockUser, [NSNull null], nil]];
 
   FlutterMethodCall *methodCall =
       [FlutterMethodCall methodCallWithMethodName:@"requestScopes"
diff --git a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m
index 5ad69e2..55d09bd 100644
--- a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m
+++ b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m
@@ -36,17 +36,28 @@
                              details:error.localizedDescription];
 }
 
-@interface FLTGoogleSignInPlugin () <GIDSignInDelegate>
+@interface FLTGoogleSignInPlugin ()
+
+// Configuration wrapping Google Cloud Console, Google Apps, OpenID,
+// and other initialization metadata.
+@property(strong) GIDConfiguration *configuration;
+
+// Permissions requested during at sign in "init" method call
+// unioned with scopes requested later with incremental authorization
+// "requestScopes" method call.
+// The "email" and "profile" base scopes are always implicitly requested.
+@property(copy) NSSet<NSString *> *requestedScopes;
+
+// Instance used to manage Google Sign In authentication including
+// sign in, sign out, and requesting additional scopes.
 @property(strong, readonly) GIDSignIn *signIn;
 
 // Redeclared as not a designated initializer.
 - (instancetype)init;
+
 @end
 
-@implementation FLTGoogleSignInPlugin {
-  FlutterResult _accountRequest;
-  NSArray<NSString *> *_additionalScopesRequest;
-}
+@implementation FLTGoogleSignInPlugin
 
 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
   FlutterMethodChannel *channel =
@@ -65,11 +76,11 @@
   self = [super init];
   if (self) {
     _signIn = signIn;
-    _signIn.delegate = self;
 
     // On the iOS simulator, we get "Broken pipe" errors after sign-in for some
     // unknown reason. We can avoid crashing the app by ignoring them.
     signal(SIGPIPE, SIG_IGN);
+    _requestedScopes = [[NSSet alloc] init];
   }
   return self;
 }
@@ -78,25 +89,14 @@
 
 - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
   if ([call.method isEqualToString:@"init"]) {
-    NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
-    if (path) {
-      NSMutableDictionary<NSString *, NSString *> *plist =
-          [[NSMutableDictionary alloc] initWithContentsOfFile:path];
-      BOOL hasDynamicClientId = [call.arguments[@"clientId"] isKindOfClass:[NSString class]];
-
-      if (hasDynamicClientId) {
-        self.signIn.clientID = call.arguments[@"clientId"];
-      } else {
-        self.signIn.clientID = plist[kClientIdKey];
+    GIDConfiguration *configuration =
+        [self configurationWithClientIdArgument:call.arguments[@"clientId"]
+                           hostedDomainArgument:call.arguments[@"hostedDomain"]];
+    if (configuration != nil) {
+      if ([call.arguments[@"scopes"] isKindOfClass:[NSArray class]]) {
+        self.requestedScopes = [NSSet setWithArray:call.arguments[@"scopes"]];
       }
-
-      self.signIn.serverClientID = plist[kServerClientIdKey];
-      self.signIn.scopes = call.arguments[@"scopes"];
-      if (call.arguments[@"hostedDomain"] == [NSNull null]) {
-        self.signIn.hostedDomain = nil;
-      } else {
-        self.signIn.hostedDomain = call.arguments[@"hostedDomain"];
-      }
+      self.configuration = configuration;
       result(nil);
     } else {
       result([FlutterError errorWithCode:@"missing-config"
@@ -104,26 +104,31 @@
                                  details:nil]);
     }
   } else if ([call.method isEqualToString:@"signInSilently"]) {
-    if ([self setAccountRequest:result]) {
-      [self.signIn restorePreviousSignIn];
-    }
+    [self.signIn restorePreviousSignInWithCallback:^(GIDGoogleUser *user, NSError *error) {
+      [self didSignInForUser:user result:result withError:error];
+    }];
   } else if ([call.method isEqualToString:@"isSignedIn"]) {
     result(@([self.signIn hasPreviousSignIn]));
   } else if ([call.method isEqualToString:@"signIn"]) {
-    self.signIn.presentingViewController = [self topViewController];
-
-    if ([self setAccountRequest:result]) {
-      @try {
-        [self.signIn signIn];
-      } @catch (NSException *e) {
-        result([FlutterError errorWithCode:@"google_sign_in" message:e.reason details:e.name]);
-        [e raise];
-      }
+    @try {
+      GIDConfiguration *configuration = self.configuration
+                                            ?: [self configurationWithClientIdArgument:nil
+                                                                  hostedDomainArgument:nil];
+      [self.signIn signInWithConfiguration:configuration
+                  presentingViewController:[self topViewController]
+                                      hint:nil
+                          additionalScopes:self.requestedScopes.allObjects
+                                  callback:^(GIDGoogleUser *user, NSError *error) {
+                                    [self didSignInForUser:user result:result withError:error];
+                                  }];
+    } @catch (NSException *e) {
+      result([FlutterError errorWithCode:@"google_sign_in" message:e.reason details:e.name]);
+      [e raise];
     }
   } else if ([call.method isEqualToString:@"getTokens"]) {
     GIDGoogleUser *currentUser = self.signIn.currentUser;
     GIDAuthentication *auth = currentUser.authentication;
-    [auth getTokensWithHandler:^void(GIDAuthentication *authentication, NSError *error) {
+    [auth doWithFreshTokens:^void(GIDAuthentication *authentication, NSError *error) {
       result(error != nil ? getFlutterError(error) : @{
         @"idToken" : authentication.idToken,
         @"accessToken" : authentication.accessToken,
@@ -133,61 +138,49 @@
     [self.signIn signOut];
     result(nil);
   } else if ([call.method isEqualToString:@"disconnect"]) {
-    if ([self setAccountRequest:result]) {
-      [self.signIn disconnect];
-    }
+    [self.signIn disconnectWithCallback:^(NSError *error) {
+      [self respondWithAccount:@{} result:result error:nil];
+    }];
   } else if ([call.method isEqualToString:@"requestScopes"]) {
-    GIDGoogleUser *user = self.signIn.currentUser;
-    if (user == nil) {
-      result([FlutterError errorWithCode:@"sign_in_required"
-                                 message:@"No account to grant scopes."
-                                 details:nil]);
-      return;
+    id scopeArgument = call.arguments[@"scopes"];
+    if ([scopeArgument isKindOfClass:[NSArray class]]) {
+      self.requestedScopes = [self.requestedScopes setByAddingObjectsFromArray:scopeArgument];
     }
+    NSSet<NSString *> *requestedScopes = self.requestedScopes;
 
-    NSArray<NSString *> *currentScopes = self.signIn.scopes;
-    NSArray<NSString *> *scopes = call.arguments[@"scopes"];
-    NSArray<NSString *> *missingScopes = [scopes
-        filteredArrayUsingPredicate:[NSPredicate
-                                        predicateWithBlock:^BOOL(id scope, NSDictionary *bindings) {
-                                          return ![user.grantedScopes containsObject:scope];
-                                        }]];
-
-    if (!missingScopes || !missingScopes.count) {
-      result(@(YES));
-      return;
-    }
-
-    if ([self setAccountRequest:result]) {
-      _additionalScopesRequest = missingScopes;
-      self.signIn.scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes];
-      self.signIn.presentingViewController = [self topViewController];
-      self.signIn.loginHint = user.profile.email;
-      @try {
-        [self.signIn signIn];
-      } @catch (NSException *e) {
-        result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]);
-      }
+    @try {
+      [self.signIn addScopes:requestedScopes.allObjects
+          presentingViewController:[self topViewController]
+                          callback:^(GIDGoogleUser *addedScopeUser, NSError *addedScopeError) {
+                            if ([addedScopeError.domain isEqualToString:kGIDSignInErrorDomain] &&
+                                addedScopeError.code == kGIDSignInErrorCodeNoCurrentUser) {
+                              result([FlutterError errorWithCode:@"sign_in_required"
+                                                         message:@"No account to grant scopes."
+                                                         details:nil]);
+                            } else if ([addedScopeError.domain
+                                           isEqualToString:kGIDSignInErrorDomain] &&
+                                       addedScopeError.code ==
+                                           kGIDSignInErrorCodeScopesAlreadyGranted) {
+                              // Scopes already granted, report success.
+                              result(@YES);
+                            } else if (addedScopeUser == nil) {
+                              result(@NO);
+                            } else {
+                              NSSet<NSString *> *grantedScopes =
+                                  [NSSet setWithArray:addedScopeUser.grantedScopes];
+                              BOOL granted = [requestedScopes isSubsetOfSet:grantedScopes];
+                              result(@(granted));
+                            }
+                          }];
+    } @catch (NSException *e) {
+      result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]);
     }
   } else {
     result(FlutterMethodNotImplemented);
   }
 }
 
-- (BOOL)setAccountRequest:(FlutterResult)request {
-  if (_accountRequest != nil) {
-    request([FlutterError errorWithCode:@"concurrent-requests"
-                                message:@"Concurrent requests to account signin"
-                                details:nil]);
-    return NO;
-  }
-  _accountRequest = request;
-  return YES;
-}
-
-- (BOOL)application:(UIApplication *)app
-            openURL:(NSURL *)url
-            options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
+- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
   return [self.signIn handleURL:url];
 }
 
@@ -203,57 +196,58 @@
   [viewController dismissViewControllerAnimated:YES completion:nil];
 }
 
-#pragma mark - <GIDSignInDelegate> protocol
+#pragma mark - private methods
 
-- (void)signIn:(GIDSignIn *)signIn
-    didSignInForUser:(GIDGoogleUser *)user
-           withError:(NSError *)error {
+/// @return @c nil if GoogleService-Info.plist not found.
+- (GIDConfiguration *)configurationWithClientIdArgument:(id)clientIDArg
+                                   hostedDomainArgument:(id)hostedDomainArg {
+  NSString *plistPath = [NSBundle.mainBundle pathForResource:@"GoogleService-Info" ofType:@"plist"];
+  if (plistPath == nil) {
+    return nil;
+  }
+
+  NSDictionary<NSString *, id> *plist = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
+
+  BOOL hasDynamicClientId = [clientIDArg isKindOfClass:[NSString class]];
+  NSString *clientID = hasDynamicClientId ? clientIDArg : plist[kClientIdKey];
+
+  NSString *hostedDomain = nil;
+  if (hostedDomainArg != [NSNull null]) {
+    hostedDomain = hostedDomainArg;
+  }
+  return [[GIDConfiguration alloc] initWithClientID:clientID
+                                     serverClientID:plist[kServerClientIdKey]
+                                       hostedDomain:hostedDomain
+                                        openIDRealm:nil];
+}
+
+- (void)didSignInForUser:(GIDGoogleUser *)user
+                  result:(FlutterResult)result
+               withError:(NSError *)error {
   if (error != nil) {
     // Forward all errors and let Dart side decide how to handle.
-    [self respondWithAccount:nil error:error];
+    [self respondWithAccount:nil result:result error:error];
   } else {
-    if (_additionalScopesRequest) {
-      bool granted = YES;
-      for (NSString *scope in _additionalScopesRequest) {
-        if (![user.grantedScopes containsObject:scope]) {
-          granted = NO;
-          break;
-        }
-      }
-      _accountRequest(@(granted));
-      _accountRequest = nil;
-      _additionalScopesRequest = nil;
-      return;
-    } else {
-      NSURL *photoUrl;
-      if (user.profile.hasImage) {
-        // Placeholder that will be replaced by on the Dart side based on screen
-        // size
-        photoUrl = [user.profile imageURLWithDimension:1337];
-      }
-      [self respondWithAccount:@{
-        @"displayName" : user.profile.name ?: [NSNull null],
-        @"email" : user.profile.email ?: [NSNull null],
-        @"id" : user.userID ?: [NSNull null],
-        @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null],
-        @"serverAuthCode" : user.serverAuthCode ?: [NSNull null]
-      }
-                         error:nil];
+    NSURL *photoUrl;
+    if (user.profile.hasImage) {
+      // Placeholder that will be replaced by on the Dart side based on screen size.
+      photoUrl = [user.profile imageURLWithDimension:1337];
     }
+    [self respondWithAccount:@{
+      @"displayName" : user.profile.name ?: [NSNull null],
+      @"email" : user.profile.email ?: [NSNull null],
+      @"id" : user.userID ?: [NSNull null],
+      @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null],
+      @"serverAuthCode" : user.serverAuthCode ?: [NSNull null]
+    }
+                      result:result
+                       error:nil];
   }
 }
 
-- (void)signIn:(GIDSignIn *)signIn
-    didDisconnectWithUser:(GIDGoogleUser *)user
-                withError:(NSError *)error {
-  [self respondWithAccount:@{} error:nil];
-}
-
-#pragma mark - private methods
-
-- (void)respondWithAccount:(NSDictionary<NSString *, id> *)account error:(NSError *)error {
-  FlutterResult result = _accountRequest;
-  _accountRequest = nil;
+- (void)respondWithAccount:(NSDictionary<NSString *, id> *)account
+                    result:(FlutterResult)result
+                     error:(NSError *)error {
   result(error != nil ? getFlutterError(error) : account);
 }
 
diff --git a/packages/google_sign_in/google_sign_in_ios/ios/google_sign_in_ios.podspec b/packages/google_sign_in/google_sign_in_ios/ios/google_sign_in_ios.podspec
index f583f6c..18a2135 100644
--- a/packages/google_sign_in/google_sign_in_ios/ios/google_sign_in_ios.podspec
+++ b/packages/google_sign_in/google_sign_in_ios/ios/google_sign_in_ios.podspec
@@ -16,11 +16,8 @@
   s.public_header_files = 'Classes/**/*.h'
   s.module_map = 'Classes/FLTGoogleSignInPlugin.modulemap'
   s.dependency 'Flutter'
-  s.dependency 'GoogleSignIn', '~> 5.0'
+  s.dependency 'GoogleSignIn', '~> 6.2'
   s.static_framework = true
-
   s.platform = :ios, '9.0'
-
-  # GoogleSignIn ~> 5.0 does not support arm64 simulators.
-  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
+  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
 end
diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml
index b6f541b..5604ee6 100644
--- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml
+++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml
@@ -1,8 +1,8 @@
 name: google_sign_in_ios
-description: Android implementation of the google_sign_in plugin.
+description: iOS implementation of the google_sign_in plugin.
 repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_ios
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
-version: 5.2.7
+version: 5.3.0
 
 environment:
   sdk: ">=2.14.0 <3.0.0"