From a0d99ee3de7c8e6a23301ac6d99ea88c4038f3ed Mon Sep 17 00:00:00 2001
From: David Iglesias <ditman@gmail.com>
Date: Thu, 25 Feb 2021 14:26:03 -0800
Subject: [PATCH] [google_sign_in_web] Migrate to null-safety (#3628)

---
 .../google_sign_in_web/CHANGELOG.md           |   4 +
 .../google_sign_in_web/example/README.md      |  21 +
 .../integration_test/auth2_test.dart}         |  19 +-
 .../integration_test/gapi_load_test.dart}     |   7 +-
 .../gapi_mocks/gapi_mocks.dart                |   0
 .../gapi_mocks/src/auth2_init.dart            |   0
 .../gapi_mocks/src/gapi.dart                  |   0
 .../gapi_mocks/src/google_user.dart           |   0
 .../gapi_mocks/src/test_iife.dart             |   0
 .../integration_test/gapi_utils_test.dart}    |  52 ++-
 .../integration_test}/src/test_utils.dart     |   0
 .../{test => example}/lib/main.dart           |   0
 .../{test => example}/pubspec.yaml            |  12 +-
 .../{test/run_test => example/run_test.sh}    |   7 +-
 .../test_driver/integration_driver.dart}      |   0
 .../{test => example}/web/index.html          |   0
 .../lib/google_sign_in_web.dart               |  64 +--
 .../lib/src/generated/gapi.dart               | 435 +-----------------
 .../lib/src/generated/gapiauth2.dart          | 257 ++++++-----
 .../google_sign_in_web/lib/src/load_gapi.dart |   2 +-
 .../google_sign_in_web/lib/src/utils.dart     |  35 +-
 .../google_sign_in_web/pubspec.yaml           |  18 +-
 .../google_sign_in_web/test/README.md         |  18 +-
 .../gapi_load_integration_test.dart           |   7 -
 .../gapi_utils_integration_test.dart          |   7 -
 .../test/tests_exist_elsewhere_test.dart      |  10 +
 26 files changed, 322 insertions(+), 653 deletions(-)
 create mode 100644 packages/google_sign_in/google_sign_in_web/example/README.md
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver/auth2_integration.dart => example/integration_test/auth2_test.dart} (91%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver/gapi_load_integration.dart => example/integration_test/gapi_load_test.dart} (92%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/gapi_mocks.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/auth2_init.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/gapi.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/google_user.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/test_iife.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver/gapi_utils_integration.dart => example/integration_test/gapi_utils_test.dart} (54%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/src/test_utils.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test => example}/lib/main.dart (100%)
 rename packages/google_sign_in/google_sign_in_web/{test => example}/pubspec.yaml (57%)
 rename packages/google_sign_in/google_sign_in_web/{test/run_test => example/run_test.sh} (57%)
 rename packages/google_sign_in/google_sign_in_web/{test/test_driver/auth2_integration_test.dart => example/test_driver/integration_driver.dart} (100%)
 rename packages/google_sign_in/google_sign_in_web/{test => example}/web/index.html (100%)
 delete mode 100644 packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart
 delete mode 100644 packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart
 create mode 100644 packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart

diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md
index d1353f723fd5..a5c9e9d2f2bb 100644
--- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md
+++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.10.0
+
+* Migrate to null-safety.
+
 ## 0.9.2+1
 
 * Update Flutter SDK constraint.
diff --git a/packages/google_sign_in/google_sign_in_web/example/README.md b/packages/google_sign_in/google_sign_in_web/example/README.md
new file mode 100644
index 000000000000..0ec01e025570
--- /dev/null
+++ b/packages/google_sign_in/google_sign_in_web/example/README.md
@@ -0,0 +1,21 @@
+# Testing
+
+This package utilizes the `integration_test` package to run its tests in a web browser.
+
+See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info.
+
+## Running the tests
+
+Make sure you have updated to the latest Flutter master.
+
+1. Check what version of Chrome is running on the machine you're running tests on.
+
+2. Download and install driver for that version from here:
+    * <https://chromedriver.chromium.org/downloads>
+
+3. Start the driver using `chromedriver --port=4444`
+
+4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux):
+
+    * Single: `./run_test.sh integration_test/TEST_NAME.dart`
+    * All: `./run_test.sh`
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart
similarity index 91%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart
index e2f16f2aee43..b80080935d42 100644
--- a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart
+++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart
@@ -3,11 +3,12 @@
 // found in the LICENSE file.
 
 import 'package:flutter/services.dart';
-import 'package:integration_test/integration_test.dart';
-
 import 'package:flutter_test/flutter_test.dart';
 import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
 import 'package:google_sign_in_web/google_sign_in_web.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:js/js_util.dart' as js_util;
+
 import 'gapi_mocks/gapi_mocks.dart' as gapi_mocks;
 import 'src/test_utils.dart';
 
@@ -25,7 +26,7 @@ void main() {
     idToken: expectedTokenData.idToken,
   );
 
-  GoogleSignInPlugin plugin;
+  late GoogleSignInPlugin plugin;
 
   group('plugin.init() throws a catchable exception', () {
     setUp(() {
@@ -54,7 +55,8 @@ void main() {
         );
         fail('plugin.init should have thrown an exception!');
       } catch (e) {
-        expect(e.code, 'idpiframe_initialization_failed');
+        final String code = js_util.getProperty(e, 'code') as String;
+        expect(code, 'idpiframe_initialization_failed');
       }
     });
   });
@@ -62,7 +64,7 @@ void main() {
   group('other methods also throw catchable exceptions on init fail', () {
     // This function ensures that init gets called, but for some reason, we
     // ignored that it has thrown stuff...
-    void _discardInit() async {
+    Future<void> _discardInit() async {
       try {
         await plugin.init(
           hostedDomain: 'foo',
@@ -135,13 +137,13 @@ void main() {
       });
 
       testWidgets('signInSilently', (WidgetTester tester) async {
-        GoogleSignInUserData actualUser = await plugin.signInSilently();
+        GoogleSignInUserData actualUser = (await plugin.signInSilently())!;
 
         expect(actualUser, expectedUserData);
       });
 
       testWidgets('signIn', (WidgetTester tester) async {
-        GoogleSignInUserData actualUser = await plugin.signIn();
+        GoogleSignInUserData actualUser = (await plugin.signIn())!;
 
         expect(actualUser, expectedUserData);
       });
@@ -185,7 +187,8 @@ void main() {
         await plugin.signIn();
         fail('plugin.signIn() should have thrown an exception!');
       } catch (e) {
-        expect(e.code, 'popup_closed_by_user');
+        final String code = js_util.getProperty(e, 'code') as String;
+        expect(code, 'popup_closed_by_user');
       }
     });
   });
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart
similarity index 92%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart
index 540369cae370..e0729bcf9b5e 100644
--- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart
+++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart
@@ -4,18 +4,19 @@
 
 import 'dart:html' as html;
 
-import 'package:integration_test/integration_test.dart';
-
 import 'package:flutter_test/flutter_test.dart';
 import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
 import 'package:google_sign_in_web/google_sign_in_web.dart';
+import 'package:integration_test/integration_test.dart';
+
 import 'gapi_mocks/gapi_mocks.dart' as gapi_mocks;
 import 'src/test_utils.dart';
 
 void main() {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  gapiUrl = toBase64Url(gapi_mocks.auth2InitSuccess(GoogleSignInUserData()));
+  gapiUrl = toBase64Url(gapi_mocks.auth2InitSuccess(
+      GoogleSignInUserData(email: 'test@test.com', id: '1234')));
 
   testWidgets('Plugin is initialized after GAPI fully loads and init is called',
       (WidgetTester tester) async {
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/gapi_mocks.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/gapi_mocks.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/auth2_init.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/auth2_init.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/gapi.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/gapi.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/google_user.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/google_user.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/test_iife.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/test_iife.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart
similarity index 54%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart
index 55b942842b33..e03974a145b7 100644
--- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart
+++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart
@@ -1,27 +1,21 @@
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-import 'package:flutter_test/flutter_test.dart';
-
-import 'package:integration_test/integration_test.dart';
 
+import 'package:flutter_test/flutter_test.dart';
 import 'package:google_sign_in_web/src/generated/gapiauth2.dart' as gapi;
 import 'package:google_sign_in_web/src/utils.dart';
-import 'package:mockito/mockito.dart';
-
-class MockGoogleUser extends Mock implements gapi.GoogleUser {}
-
-class MockBasicProfile extends Mock implements gapi.BasicProfile {}
+import 'package:integration_test/integration_test.dart';
 
 void main() {
   // The non-null use cases are covered by the auth2_test.dart file.
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
   group('gapiUserToPluginUserData', () {
-    var mockUser;
+    late FakeGoogleUser fakeUser;
 
     setUp(() {
-      mockUser = MockGoogleUser();
+      fakeUser = FakeGoogleUser();
     });
 
     testWidgets('null user -> null response', (WidgetTester tester) async {
@@ -30,21 +24,45 @@ void main() {
 
     testWidgets('not signed-in user -> null response',
         (WidgetTester tester) async {
-      when(mockUser.isSignedIn()).thenReturn(false);
-      expect(gapiUserToPluginUserData(mockUser), isNull);
+      expect(gapiUserToPluginUserData(fakeUser), isNull);
     });
 
     testWidgets('signed-in, but null profile user -> null response',
         (WidgetTester tester) async {
-      when(mockUser.isSignedIn()).thenReturn(true);
-      expect(gapiUserToPluginUserData(mockUser), isNull);
+      fakeUser.setIsSignedIn(true);
+      expect(gapiUserToPluginUserData(fakeUser), isNull);
     });
 
     testWidgets('signed-in, null userId in profile user -> null response',
         (WidgetTester tester) async {
-      when(mockUser.isSignedIn()).thenReturn(true);
-      when(mockUser.getBasicProfile()).thenReturn(MockBasicProfile());
-      expect(gapiUserToPluginUserData(mockUser), isNull);
+      fakeUser.setIsSignedIn(true);
+      fakeUser.setBasicProfile(FakeBasicProfile());
+      expect(gapiUserToPluginUserData(fakeUser), isNull);
     });
   });
 }
+
+class FakeGoogleUser extends Fake implements gapi.GoogleUser {
+  bool _isSignedIn = false;
+  gapi.BasicProfile? _basicProfile;
+
+  @override
+  bool isSignedIn() => _isSignedIn;
+  @override
+  gapi.BasicProfile? getBasicProfile() => _basicProfile;
+
+  void setIsSignedIn(bool isSignedIn) {
+    _isSignedIn = isSignedIn;
+  }
+
+  void setBasicProfile(gapi.BasicProfile basicProfile) {
+    _basicProfile = basicProfile;
+  }
+}
+
+class FakeBasicProfile extends Fake implements gapi.BasicProfile {
+  String? _id;
+
+  @override
+  String? getId() => _id;
+}
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/src/test_utils.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/src/test_utils.dart
rename to packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/lib/main.dart b/packages/google_sign_in/google_sign_in_web/example/lib/main.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/lib/main.dart
rename to packages/google_sign_in/google_sign_in_web/example/lib/main.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/example/pubspec.yaml
similarity index 57%
rename from packages/google_sign_in/google_sign_in_web/test/pubspec.yaml
rename to packages/google_sign_in/google_sign_in_web/example/pubspec.yaml
index dd0354e81498..385b2ea0861e 100644
--- a/packages/google_sign_in/google_sign_in_web/test/pubspec.yaml
+++ b/packages/google_sign_in/google_sign_in_web/example/pubspec.yaml
@@ -1,23 +1,23 @@
-name: regular_integration_tests
+name: google_sign_in_web_integration_tests
 publish_to: none
 
 environment:
-  sdk: ">=2.2.2 <3.0.0"
+  sdk: ">=2.12.0-259.9.beta <3.0.0"
+  flutter: ">=1.27.0-0" # For integration_test from sdk
 
 dependencies:
   flutter:
     sdk: flutter
 
 dev_dependencies:
-  google_sign_in: ^4.5.3
+  http: ^0.13.0
+  js: ^0.6.3
   flutter_driver:
     sdk: flutter
   flutter_test:
     sdk: flutter
-  http: ^0.12.2
-  mockito: ^4.1.1
   integration_test:
-    path: ../../../integration_test
+    sdk: flutter
 
 dependency_overrides:
   google_sign_in_web:
diff --git a/packages/google_sign_in/google_sign_in_web/test/run_test b/packages/google_sign_in/google_sign_in_web/example/run_test.sh
similarity index 57%
rename from packages/google_sign_in/google_sign_in_web/test/run_test
rename to packages/google_sign_in/google_sign_in_web/example/run_test.sh
index 74a8526a0fa3..0f76f4a47e16 100755
--- a/packages/google_sign_in/google_sign_in_web/test/run_test
+++ b/packages/google_sign_in/google_sign_in_web/example/run_test.sh
@@ -1,17 +1,20 @@
 #!/usr/bin/bash
+
 if pgrep -lf chromedriver > /dev/null; then
   echo "chromedriver is running."
 
   if [ $# -eq 0 ]; then
     echo "No target specified, running all tests..."
-    find test_driver/ -iname *_integration.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --target='{}'
+    find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome  --driver=test_driver/integration_driver.dart --target='{}'
   else
     echo "Running test target: $1..."
     set -x
-    flutter drive -d web-server --web-port=7357 --browser-name=chrome --target=$1
+    flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1
   fi
 
   else
     echo "chromedriver is not running."
 fi
 
+
+
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration_test.dart b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration_test.dart
rename to packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart
diff --git a/packages/google_sign_in/google_sign_in_web/test/web/index.html b/packages/google_sign_in/google_sign_in_web/example/web/index.html
similarity index 100%
rename from packages/google_sign_in/google_sign_in_web/test/web/index.html
rename to packages/google_sign_in/google_sign_in_web/example/web/index.html
diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart
index dd82852fa350..41e8106802de 100644
--- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart
+++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart
@@ -6,8 +6,8 @@ import 'dart:async';
 import 'dart:html' as html;
 
 import 'package:flutter/services.dart';
-import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
 import 'package:flutter_web_plugins/flutter_web_plugins.dart';
+import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
 import 'package:js/js.dart';
 import 'package:meta/meta.dart';
 
@@ -37,8 +37,8 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
     _isGapiInitialized = gapi.inject(gapiUrl).then((_) => gapi.init());
   }
 
-  Future<void> _isGapiInitialized;
-  Future<void> _isAuthInitialized;
+  late Future<void> _isGapiInitialized;
+  late Future<void> _isAuthInitialized;
   bool _isInitCalled = false;
 
   // This method throws if init hasn't been called at some point in the past.
@@ -58,7 +58,7 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
     return Future.wait([_isGapiInitialized, _isAuthInitialized]);
   }
 
-  String _autoDetectedClientId;
+  String? _autoDetectedClientId;
 
   /// Factory method that initializes the plugin with [GoogleSignInPlatform].
   static void registerWith(Registrar registrar) {
@@ -66,12 +66,13 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
   }
 
   @override
-  Future<void> init(
-      {@required String hostedDomain,
-      List<String> scopes = const <String>[],
-      SignInOption signInOption = SignInOption.standard,
-      String clientId}) async {
-    final String appClientId = clientId ?? _autoDetectedClientId;
+  Future<void> init({
+    List<String> scopes = const <String>[],
+    SignInOption signInOption = SignInOption.standard,
+    String? hostedDomain,
+    String? clientId,
+  }) async {
+    final String? appClientId = clientId ?? _autoDetectedClientId;
     assert(
         appClientId != null,
         'ClientID not set. Either set it on a '
@@ -90,7 +91,7 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
       hosted_domain: hostedDomain,
       // The js lib wants a space-separated list of values
       scope: scopes.join(' '),
-      client_id: appClientId,
+      client_id: appClientId!,
     ));
 
     Completer<void> isAuthInitialized = Completer<void>();
@@ -119,18 +120,18 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
   }
 
   @override
-  Future<GoogleSignInUserData> signInSilently() async {
+  Future<GoogleSignInUserData?> signInSilently() async {
     await initialized;
 
     return gapiUserToPluginUserData(
-        await auth2.getAuthInstance().currentUser.get());
+        await auth2.getAuthInstance()?.currentUser?.get());
   }
 
   @override
-  Future<GoogleSignInUserData> signIn() async {
+  Future<GoogleSignInUserData?> signIn() async {
     await initialized;
     try {
-      return gapiUserToPluginUserData(await auth2.getAuthInstance().signIn());
+      return gapiUserToPluginUserData(await auth2.getAuthInstance()?.signIn());
     } on auth2.GoogleAuthSignInError catch (reason) {
       throw PlatformException(
         code: reason.error,
@@ -143,30 +144,33 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
 
   @override
   Future<GoogleSignInTokenData> getTokens(
-      {@required String email, bool shouldRecoverAuth}) async {
+      {required String email, bool? shouldRecoverAuth}) async {
     await initialized;
 
-    final auth2.GoogleUser currentUser =
+    final auth2.GoogleUser? currentUser =
         auth2.getAuthInstance()?.currentUser?.get();
-    final auth2.AuthResponse response = currentUser.getAuthResponse();
+    final auth2.AuthResponse? response = currentUser?.getAuthResponse();
 
     return GoogleSignInTokenData(
-        idToken: response.id_token, accessToken: response.access_token);
+        idToken: response?.id_token, accessToken: response?.access_token);
   }
 
   @override
   Future<void> signOut() async {
     await initialized;
 
-    return auth2.getAuthInstance().signOut();
+    return auth2.getAuthInstance()?.signOut();
   }
 
   @override
   Future<void> disconnect() async {
     await initialized;
 
-    final auth2.GoogleUser currentUser =
+    final auth2.GoogleUser? currentUser =
         auth2.getAuthInstance()?.currentUser?.get();
+
+    if (currentUser == null) return;
+
     return currentUser.disconnect();
   }
 
@@ -174,16 +178,19 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
   Future<bool> isSignedIn() async {
     await initialized;
 
-    final auth2.GoogleUser currentUser =
+    final auth2.GoogleUser? currentUser =
         auth2.getAuthInstance()?.currentUser?.get();
+
+    if (currentUser == null) return false;
+
     return currentUser.isSignedIn();
   }
 
   @override
-  Future<void> clearAuthCache({String token}) async {
+  Future<void> clearAuthCache({required String token}) async {
     await initialized;
 
-    return auth2.getAuthInstance().disconnect();
+    return auth2.getAuthInstance()?.disconnect();
   }
 
   @override
@@ -194,14 +201,15 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
 
     if (currentUser == null) return false;
 
-    final grantedScopes = currentUser.getGrantedScopes();
+    final grantedScopes = currentUser.getGrantedScopes() ?? '';
     final missingScopes =
         scopes.where((scope) => !grantedScopes.contains(scope));
 
     if (missingScopes.isEmpty) return true;
 
-    return currentUser
-            .grant(auth2.SigninOptions(scope: missingScopes.join(" "))) ??
-        false;
+    final response = await currentUser
+        .grant(auth2.SigninOptions(scope: missingScopes.join(' ')));
+
+    return response != null;
   }
 }
diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart
index 95f07490d3e6..f0f886ce7880 100644
--- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart
+++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart
@@ -2,448 +2,53 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// ignore_for_file: public_member_api_docs, unused_element
-
-@JS()
-library gapi;
-
-import "package:js/js.dart";
-import "package:js/js_util.dart" show promiseToFuture;
-
 /// Type definitions for Google API Client
 /// Project: https://github.com/google/google-api-javascript-client
 /// Definitions by: Frank M <https://github.com/sgtfrankieboy>, grant <https://github.com/grant>
 /// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
 /// TypeScript Version: 2.3
 
-/// The OAuth 2.0 token object represents the OAuth 2.0 token and any associated data.
-@anonymous
-@JS()
-abstract class GoogleApiOAuth2TokenObject {
-  /// The OAuth 2.0 token. Only present in successful responses
-  external String get access_token;
-  external set access_token(String v);
-
-  /// Details about the error. Only present in error responses
-  external String get error;
-  external set error(String v);
-
-  /// The duration, in seconds, the token is valid for. Only present in successful responses
-  external String get expires_in;
-  external set expires_in(String v);
-  external GoogleApiOAuth2TokenSessionState get session_state;
-  external set session_state(GoogleApiOAuth2TokenSessionState v);
+// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/gapi
 
-  /// The Google API scopes related to this token
-  external String get state;
-  external set state(String v);
-  external factory GoogleApiOAuth2TokenObject(
-      {String access_token,
-      String error,
-      String expires_in,
-      GoogleApiOAuth2TokenSessionState session_state,
-      String state});
-}
+// ignore_for_file: public_member_api_docs, unused_element
 
-@anonymous
 @JS()
-abstract class GoogleApiOAuth2TokenSessionState {
-  external dynamic /*{
-        authuser: string,
-    }*/
-      get extraQueryParams;
-  external set extraQueryParams(
-      dynamic
-          /*{
-        authuser: string,
-    }*/
-          v);
-  external factory GoogleApiOAuth2TokenSessionState(
-      {dynamic
-          /*{
-        authuser: string,
-    }*/
-          extraQueryParams});
-}
+library gapi;
 
-/// Fix for #8215
-/// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/8215
-/// Usage example:
-/// https://developers.google.com/identity/sign-in/web/session-state
+import 'package:js/js.dart';
 
 // Module gapi
 typedef void LoadCallback(
-    [dynamic args1,
-    dynamic args2,
-    dynamic args3,
-    dynamic args4,
-    dynamic args5]);
+    [dynamic? args1,
+    dynamic? args2,
+    dynamic? args3,
+    dynamic? args4,
+    dynamic? args5]);
 
 @anonymous
 @JS()
 abstract class LoadConfig {
   external LoadCallback get callback;
   external set callback(LoadCallback v);
-  external Function get onerror;
-  external set onerror(Function v);
-  external num get timeout;
-  external set timeout(num v);
-  external Function get ontimeout;
-  external set ontimeout(Function v);
+  external Function? get onerror;
+  external set onerror(Function? v);
+  external num? get timeout;
+  external set timeout(num? v);
+  external Function? get ontimeout;
+  external set ontimeout(Function? v);
   external factory LoadConfig(
       {LoadCallback callback,
-      Function onerror,
-      num timeout,
-      Function ontimeout});
+      Function? onerror,
+      num? timeout,
+      Function? ontimeout});
 }
 
 /*type CallbackOrConfig = LoadConfig | LoadCallback;*/
 /// Pragmatically initialize gapi class member.
 /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig
-@JS("gapi.load")
+@JS('gapi.load')
 external void load(
     String apiName, dynamic /*LoadConfig|LoadCallback*/ callback);
 // End module gapi
 
-// Module gapi.auth
-/// Initiates the OAuth 2.0 authorization process. The browser displays a popup window prompting the user authenticate and authorize. After the user authorizes, the popup closes and the callback function fires.
-@JS("gapi.auth.authorize")
-external void authorize(
-    dynamic
-        /*{
-        /**
-         * The application's client ID.
-         */
-        client_id?: string;
-        /**
-         * If true, then login uses "immediate mode", which means that the token is refreshed behind the scenes, and no UI is shown to the user.
-         */
-        immediate?: boolean;
-        /**
-         * The OAuth 2.0 response type property. Default: token
-         */
-        response_type?: string;
-        /**
-         * The auth scope or scopes to authorize. Auth scopes for individual APIs can be found in their documentation.
-         */
-        scope?: any;
-        /**
-         * The user to sign in as. -1 to toggle a multi-account chooser, 0 to default to the user's current account, and 1 to automatically sign in if the user is signed into Google Plus.
-         */
-        authuser?: number;
-    }*/
-        params,
-    dynamic callback(GoogleApiOAuth2TokenObject token));
-
-/// Initializes the authorization feature. Call this when the client loads to prevent popup blockers from blocking the auth window on gapi.auth.authorize calls.
-@JS("gapi.auth.init")
-external void init(dynamic callback());
-
-/// Retrieves the OAuth 2.0 token for the application.
-@JS("gapi.auth.getToken")
-external GoogleApiOAuth2TokenObject getToken();
-
-/// Sets the OAuth 2.0 token for the application.
-@JS("gapi.auth.setToken")
-external void setToken(GoogleApiOAuth2TokenObject token);
-
-/// Initiates the client-side Google+ Sign-In OAuth 2.0 flow.
-/// When the method is called, the OAuth 2.0 authorization dialog is displayed to the user and when they accept, the callback function is called.
-@JS("gapi.auth.signIn")
-external void signIn(
-    dynamic
-        /*{
-        /**
-         * Your OAuth 2.0 client ID that you obtained from the Google Developers Console.
-         */
-        clientid?: string;
-        /**
-         * Directs the sign-in button to store user and session information in a session cookie and HTML5 session storage on the user's client for the purpose of minimizing HTTP traffic and distinguishing between multiple Google accounts a user might be signed into.
-         */
-        cookiepolicy?: string;
-        /**
-         * A function in the global namespace, which is called when the sign-in button is rendered and also called after a sign-in flow completes.
-         */
-        callback?: () => void;
-        /**
-         * If true, all previously granted scopes remain granted in each incremental request, for incremental authorization. The default value true is correct for most use cases; use false only if employing delegated auth, where you pass the bearer token to a less-trusted component with lower programmatic authority.
-         */
-        includegrantedscopes?: boolean;
-        /**
-         * If your app will write moments, list the full URI of the types of moments that you intend to write.
-         */
-        requestvisibleactions?: any;
-        /**
-         * The OAuth 2.0 scopes for the APIs that you would like to use as a space-delimited list.
-         */
-        scope?: any;
-        /**
-         * If you have an Android app, you can drive automatic Android downloads from your web sign-in flow.
-         */
-        apppackagename?: string;
-    }*/
-        params);
-
-/// Signs a user out of your app without logging the user out of Google. This method will only work when the user is signed in with Google+ Sign-In.
-@JS("gapi.auth.signOut")
-external void signOut();
-// End module gapi.auth
-
-// Module gapi.client
-@anonymous
-@JS()
-abstract class RequestOptions {
-  /// The URL to handle the request
-  external String get path;
-  external set path(String v);
-
-  /// The HTTP request method to use. Default is GET
-  external String get method;
-  external set method(String v);
-
-  /// URL params in key-value pair form
-  external dynamic get params;
-  external set params(dynamic v);
-
-  /// Additional HTTP request headers
-  external dynamic get headers;
-  external set headers(dynamic v);
-
-  /// The HTTP request body (applies to PUT or POST).
-  external dynamic get body;
-  external set body(dynamic v);
-
-  /// If supplied, the request is executed immediately and no gapi.client.HttpRequest object is returned
-  external dynamic Function() get callback;
-  external set callback(dynamic Function() v);
-  external factory RequestOptions(
-      {String path,
-      String method,
-      dynamic params,
-      dynamic headers,
-      dynamic body,
-      dynamic Function() callback});
-}
-
-@anonymous
-@JS()
-abstract class _RequestOptions {
-  @JS("gapi.client.init")
-  external Promise<void> client_init(
-      dynamic
-          /*{
-        /**
-         * The API Key to use.
-         */
-        apiKey?: string;
-        /**
-         * An array of discovery doc URLs or discovery doc JSON objects.
-         */
-        discoveryDocs?: string[];
-        /**
-         * The app's client ID, found and created in the Google Developers Console.
-         */
-        clientId?: string;
-        /**
-         * The scopes to request, as a space-delimited string.
-         */
-        scope?: string,
-
-        hosted_domain?: string;
-    }*/
-          args);
-}
-
-extension RequestOptionsExtensions on RequestOptions {}
-
-@anonymous
-@JS()
-abstract class TokenObject {
-  /// The access token to use in requests.
-  external String get access_token;
-  external set access_token(String v);
-  external factory TokenObject({String access_token});
-}
-
-/// Creates a HTTP request for making RESTful requests.
-/// An object encapsulating the various arguments for this method.
-@JS("gapi.client.request")
-external HttpRequest<dynamic> request(RequestOptions args);
-
-/// Creates an RPC Request directly. The method name and version identify the method to be executed and the RPC params are provided upon RPC creation.
-@JS("gapi.client.rpcRequest")
-external RpcRequest rpcRequest(String method,
-    [String version, dynamic rpcParams]);
-
-/// Sets the API key for the application.
-@JS("gapi.client.setApiKey")
-external void setApiKey(String apiKey);
-
-/// Retrieves the OAuth 2.0 token for the application.
-@JS("gapi.client.getToken")
-external GoogleApiOAuth2TokenObject client_getToken();
-
-/// Sets the authentication token to use in requests.
-/// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientsettokentokenobject
-@JS("gapi.client.setToken")
-external void client_setToken(TokenObject /*TokenObject|Null*/ token);
-
-@anonymous
-@JS()
-abstract class HttpRequestFulfilled<T> {
-  external T get result;
-  external set result(T v);
-  external String get body;
-  external set body(String v);
-  external List<dynamic> get headers;
-  external set headers(List<dynamic> v);
-  external num get status;
-  external set status(num v);
-  external String get statusText;
-  external set statusText(String v);
-  external factory HttpRequestFulfilled(
-      {T result,
-      String body,
-      List<dynamic> headers,
-      num status,
-      String statusText});
-}
-
-@anonymous
-@JS()
-abstract class _HttpRequestFulfilled<T> {
-  /*external Promise<void> client_load(String name, String version);*/
-  /*external void client_load(String name, String version, dynamic callback(),
-    [String url]);
-*/
-  @JS("gapi.client.load")
-  external dynamic /*Promise<void>|void*/ client_load(
-      String name, String version,
-      [dynamic callback(), String url]);
-}
-
-extension HttpRequestFulfilledExtensions<T> on HttpRequestFulfilled<T> {}
-
-@anonymous
-@JS()
-abstract class HttpRequestRejected {
-  external dynamic /*dynamic|bool*/ get result;
-  external set result(dynamic /*dynamic|bool*/ v);
-  external String get body;
-  external set body(String v);
-  external List<dynamic> get headers;
-  external set headers(List<dynamic> v);
-  external num get status;
-  external set status(num v);
-  external String get statusText;
-  external set statusText(String v);
-  external factory HttpRequestRejected(
-      {dynamic /*dynamic|bool*/ result,
-      String body,
-      List<dynamic> headers,
-      num status,
-      String statusText});
-}
-
-/// HttpRequest supports promises.
-/// See Google API Client JavaScript Using Promises https://developers.google.com/api-client-library/javascript/features/promises
-@JS("gapi.client.HttpRequestPromise")
-class HttpRequestPromise<T> {}
-
-@JS("gapi.client.HttpRequestPromise")
-abstract class _HttpRequestPromise<T> {
-  /// Taken and adapted from https://github.com/Microsoft/TypeScript/blob/v2.3.1/lib/lib.es5.d.ts#L1343
-  external Promise<dynamic /*TResult1|TResult2*/ > then/*<TResult1, TResult2>*/(
-      [dynamic /*TResult1|PromiseLike<TResult1> Function(HttpRequestFulfilled<T>)|dynamic|Null*/ onfulfilled,
-      dynamic /*TResult2|PromiseLike<TResult2> Function(HttpRequestRejected)|dynamic|Null*/ onrejected,
-      dynamic opt_context]);
-}
-
-extension HttpRequestPromiseExtensions<T> on HttpRequestPromise<T> {
-  Future<dynamic /*TResult1|TResult2*/ > then(
-      [dynamic /*TResult1|PromiseLike<TResult1> Function(HttpRequestFulfilled<T>)|dynamic|Null*/ onfulfilled,
-      dynamic /*TResult2|PromiseLike<TResult2> Function(HttpRequestRejected)|dynamic|Null*/ onrejected,
-      dynamic opt_context]) {
-    final Object t = this;
-    final _HttpRequestPromise<T> tt = t;
-    return promiseToFuture(tt.then(onfulfilled, onrejected, opt_context));
-  }
-}
-
-/// An object encapsulating an HTTP request. This object is not instantiated directly, rather it is returned by gapi.client.request.
-@JS("gapi.client.HttpRequest")
-class HttpRequest<T> extends HttpRequestPromise<T> {
-  /// Executes the request and runs the supplied callback on response.
-  external void execute(
-      dynamic callback(
-
-          /// contains the response parsed as JSON. If the response is not JSON, this field will be false.
-          T jsonResp,
-
-          /// is the HTTP response. It is JSON, and can be parsed to an object
-          dynamic
-              /*{
-                body: string;
-                headers: any[];
-                status: number;
-                statusText: string;
-            }*/
-              rawResp));
-}
-
-/// Represents an HTTP Batch operation. Individual HTTP requests are added with the add method and the batch is executed using execute.
-@JS("gapi.client.HttpBatch")
-class HttpBatch {
-  /// Adds a gapi.client.HttpRequest to the batch.
-  external void add(HttpRequest<dynamic> httpRequest,
-      [dynamic
-          /*{
-            /**
-             * Identifies the response for this request in the map of batch responses. If one is not provided, the system generates a random ID.
-             */
-            id: string;
-            callback: (
-                /**
-                 * is the response for this request only. Its format is defined by the API method being called.
-                 */
-                individualResponse: any,
-                /**
-                 * is the raw batch ID-response map as a string. It contains all responses to all requests in the batch.
-                 */
-                rawBatchResponse: any
-                ) => any
-        }*/
-          opt_params]);
-
-  /// Executes all requests in the batch. The supplied callback is executed on success or failure.
-  external void execute(
-      dynamic callback(
-
-          /// is an ID-response map of each requests response.
-          dynamic responseMap,
-
-          /// is the same response, but as an unparsed JSON-string.
-          String rawBatchResponse));
-}
-
-/// Similar to gapi.client.HttpRequest except this object encapsulates requests generated by registered methods.
-@JS("gapi.client.RpcRequest")
-class RpcRequest {
-  /// Executes the request and runs the supplied callback with the response.
-  external void callback(
-      void callback(
-
-          /// contains the response parsed as JSON. If the response is not JSON, this field will be false.
-          dynamic jsonResp,
-
-          /// is the same as jsonResp, except it is a raw string that has not been parsed. It is typically used when the response is not JSON.
-          String rawResp));
-}
-
-// End module gapi.client
-@JS()
-abstract class Promise<T> {
-  external factory Promise(
-      void executor(void resolve(T result), Function reject));
-  external Promise then(void onFulfilled(T result), [Function onRejected]);
-}
+// Manually removed gapi.auth and gapi.client, unused by this plugin.
diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart
index 8c8d23378e3e..b2b5c368b6ab 100644
--- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart
+++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart
@@ -2,14 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// ignore_for_file: public_member_api_docs, unused_element
-
-@JS()
-library gapiauth2;
-
-import "package:js/js.dart";
-import "package:js/js_util.dart" show promiseToFuture;
-
 /// Type definitions for non-npm package Google Sign-In API 0.0
 /// Project: https://developers.google.com/identity/sign-in/web/
 /// Definitions by: Derek Lawless <https://github.com/flawless2011>
@@ -18,14 +10,24 @@ import "package:js/js_util.dart" show promiseToFuture;
 
 /// <reference types="gapi" />
 
+// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/gapi.auth2
+
+// ignore_for_file: public_member_api_docs, unused_element
+
+@JS()
+library gapiauth2;
+
+import 'package:js/js.dart';
+import 'package:js/js_util.dart' show promiseToFuture;
+
 @anonymous
 @JS()
 class GoogleAuthInitFailureError {
   external String get error;
-  external set error(String value);
+  external set error(String? value);
 
   external String get details;
-  external set details(String value);
+  external set details(String? value);
 }
 
 @anonymous
@@ -35,16 +37,23 @@ class GoogleAuthSignInError {
   external set error(String value);
 }
 
+@anonymous
+@JS()
+class OfflineAccessResponse {
+  external String? get code;
+  external set code(String? value);
+}
+
 // Module gapi.auth2
 /// GoogleAuth is a singleton class that provides methods to allow the user to sign in with a Google account,
 /// get the user's current sign-in status, get specific data from the user's Google profile,
 /// request additional scopes, and sign out from the current account.
-@JS("gapi.auth2.GoogleAuth")
+@JS('gapi.auth2.GoogleAuth')
 class GoogleAuth {
   external IsSignedIn get isSignedIn;
   external set isSignedIn(IsSignedIn v);
-  external CurrentUser get currentUser;
-  external set currentUser(CurrentUser v);
+  external CurrentUser? get currentUser;
+  external set currentUser(CurrentUser? v);
 
   /// Calls the onInit function when the GoogleAuth object is fully initialized, or calls the onFailure function if
   /// initialization fails.
@@ -59,7 +68,7 @@ class GoogleAuth {
 
   /// Attaches the sign-in flow to the specified container's click handler.
   external dynamic attachClickHandler(
-      dynamic container,
+      dynamic? container,
       SigninOptions options,
       dynamic onsuccess(GoogleUser googleUser),
       dynamic onfailure(String reason));
@@ -70,22 +79,20 @@ class GoogleAuth {
 abstract class _GoogleAuth {
   external Promise<GoogleUser> signIn(
       [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]);
-  external Promise<dynamic /*{code: string}*/ > grantOfflineAccess(
-      [OfflineAccessOptions options]);
+  external Promise<OfflineAccessResponse> grantOfflineAccess(
+      [OfflineAccessOptions? options]);
 }
 
 extension GoogleAuthExtensions on GoogleAuth {
   Future<GoogleUser> signIn(
       [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]) {
-    final Object t = this;
-    final _GoogleAuth tt = t;
+    final _GoogleAuth tt = this as _GoogleAuth;
     return promiseToFuture(tt.signIn(options));
   }
 
-  Future<dynamic /*{code: string}*/ > grantOfflineAccess(
-      [OfflineAccessOptions options]) {
-    final Object t = this;
-    final _GoogleAuth tt = t;
+  Future<OfflineAccessResponse> grantOfflineAccess(
+      [OfflineAccessOptions? options]) {
+    final _GoogleAuth tt = this as _GoogleAuth;
     return promiseToFuture(tt.grantOfflineAccess(options));
   }
 }
@@ -118,42 +125,52 @@ abstract class SigninOptions {
   /// The package name of the Android app to install over the air.
   /// See Android app installs from your web site:
   /// https://developers.google.com/identity/sign-in/web/android-app-installs
-  external String get app_package_name;
-  external set app_package_name(String v);
+  external String? get app_package_name;
+  external set app_package_name(String? v);
 
   /// Fetch users' basic profile information when they sign in.
   /// Adds 'profile', 'email' and 'openid' to the requested scopes.
   /// True if unspecified.
-  external bool get fetch_basic_profile;
-  external set fetch_basic_profile(bool v);
+  external bool? get fetch_basic_profile;
+  external set fetch_basic_profile(bool? v);
 
   /// Specifies whether to prompt the user for re-authentication.
   /// See OpenID Connect Request Parameters:
   /// https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters
-  external String get prompt;
-  external set prompt(String v);
+  external String? get prompt;
+  external set prompt(String? v);
 
   /// The scopes to request, as a space-delimited string.
   /// Optional if fetch_basic_profile is not set to false.
-  external String get scope;
-  external set scope(String v);
+  external String? get scope;
+  external set scope(String? v);
 
   /// The UX mode to use for the sign-in flow.
   /// By default, it will open the consent flow in a popup.
-  external String /*'popup'|'redirect'*/ get ux_mode;
-  external set ux_mode(String /*'popup'|'redirect'*/ v);
+  external String? /*'popup'|'redirect'*/ get ux_mode;
+  external set ux_mode(String? /*'popup'|'redirect'*/ v);
 
   /// If using ux_mode='redirect', this parameter allows you to override the default redirect_uri that will be used at the end of the consent flow.
   /// The default redirect_uri is the current URL stripped of query parameters and hash fragment.
-  external String get redirect_uri;
-  external set redirect_uri(String v);
+  external String? get redirect_uri;
+  external set redirect_uri(String? v);
+
+  // When your app knows which user it is trying to authenticate, it can provide this parameter as a hint to the authentication server.
+  // Passing this hint suppresses the account chooser and either pre-fill the email box on the sign-in form, or select the proper session (if the user is using multiple sign-in),
+  // which can help you avoid problems that occur if your app logs in the wrong user account. The value can be either an email address or the sub string,
+  // which is equivalent to the user's Google ID.
+  // https://developers.google.com/identity/protocols/OpenIDConnect?hl=en#authenticationuriparameters
+  external String? get login_hint;
+  external set login_hint(String? v);
+
   external factory SigninOptions(
       {String app_package_name,
       bool fetch_basic_profile,
       String prompt,
       String scope,
       String /*'popup'|'redirect'*/ ux_mode,
-      String redirect_uri});
+      String redirect_uri,
+      String login_hint});
 }
 
 /// Definitions by: John <https://github.com/jhcao23>
@@ -162,12 +179,12 @@ abstract class SigninOptions {
 @anonymous
 @JS()
 abstract class OfflineAccessOptions {
-  external String get scope;
-  external set scope(String v);
-  external String /*'select_account'|'consent'*/ get prompt;
-  external set prompt(String /*'select_account'|'consent'*/ v);
-  external String get app_package_name;
-  external set app_package_name(String v);
+  external String? get scope;
+  external set scope(String? v);
+  external String? /*'select_account'|'consent'*/ get prompt;
+  external set prompt(String? /*'select_account'|'consent'*/ v);
+  external String? get app_package_name;
+  external set app_package_name(String? v);
   external factory OfflineAccessOptions(
       {String scope,
       String /*'select_account'|'consent'*/ prompt,
@@ -180,98 +197,99 @@ abstract class OfflineAccessOptions {
 @JS()
 abstract class ClientConfig {
   /// The app's client ID, found and created in the Google Developers Console.
-  external String get client_id;
-  external set client_id(String v);
+  external String? get client_id;
+  external set client_id(String? v);
 
   /// The domains for which to create sign-in cookies. Either a URI, single_host_origin, or none.
   /// Defaults to single_host_origin if unspecified.
-  external String get cookie_policy;
-  external set cookie_policy(String v);
+  external String? get cookie_policy;
+  external set cookie_policy(String? v);
 
   /// The scopes to request, as a space-delimited string. Optional if fetch_basic_profile is not set to false.
-  external String get scope;
-  external set scope(String v);
+  external String? get scope;
+  external set scope(String? v);
 
   /// Fetch users' basic profile information when they sign in. Adds 'profile' and 'email' to the requested scopes. True if unspecified.
-  external bool get fetch_basic_profile;
-  external set fetch_basic_profile(bool v);
+  external bool? get fetch_basic_profile;
+  external set fetch_basic_profile(bool? v);
 
   /// The Google Apps domain to which users must belong to sign in. This is susceptible to modification by clients,
   /// so be sure to verify the hosted domain property of the returned user. Use GoogleUser.getHostedDomain() on the client,
   /// and the hd claim in the ID Token on the server to verify the domain is what you expected.
-  external String get hosted_domain;
-  external set hosted_domain(String v);
+  external String? get hosted_domain;
+  external set hosted_domain(String? v);
 
   /// Used only for OpenID 2.0 client migration. Set to the value of the realm that you are currently using for OpenID 2.0,
   /// as described in <a href="https://developers.google.com/accounts/docs/OpenID#openid-connect">OpenID 2.0 (Migration)</a>.
-  external String get openid_realm;
-  external set openid_realm(String v);
+  external String? get openid_realm;
+  external set openid_realm(String? v);
 
   /// The UX mode to use for the sign-in flow.
   /// By default, it will open the consent flow in a popup.
-  external String /*'popup'|'redirect'*/ get ux_mode;
-  external set ux_mode(String /*'popup'|'redirect'*/ v);
+  external String? /*'popup'|'redirect'*/ get ux_mode;
+  external set ux_mode(String? /*'popup'|'redirect'*/ v);
 
   /// If using ux_mode='redirect', this parameter allows you to override the default redirect_uri that will be used at the end of the consent flow.
   /// The default redirect_uri is the current URL stripped of query parameters and hash fragment.
-  external String get redirect_uri;
-  external set redirect_uri(String v);
+  external String? get redirect_uri;
+  external set redirect_uri(String? v);
   external factory ClientConfig(
       {String client_id,
       String cookie_policy,
       String scope,
       bool fetch_basic_profile,
-      String hosted_domain,
+      String? hosted_domain,
       String openid_realm,
       String /*'popup'|'redirect'*/ ux_mode,
       String redirect_uri});
 }
 
-@JS("gapi.auth2.SigninOptionsBuilder")
+@JS('gapi.auth2.SigninOptionsBuilder')
 class SigninOptionsBuilder {
   external dynamic setAppPackageName(String name);
   external dynamic setFetchBasicProfile(bool fetch);
   external dynamic setPrompt(String prompt);
   external dynamic setScope(String scope);
+  external dynamic setLoginHint(String hint);
 }
 
 @anonymous
 @JS()
 abstract class BasicProfile {
-  external String getId();
-  external String getName();
-  external String getGivenName();
-  external String getFamilyName();
-  external String getImageUrl();
-  external String getEmail();
+  external String? getId();
+  external String? getName();
+  external String? getGivenName();
+  external String? getFamilyName();
+  external String? getImageUrl();
+  external String? getEmail();
 }
 
 /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authresponse
 @anonymous
 @JS()
 abstract class AuthResponse {
-  external String get access_token;
-  external set access_token(String v);
-  external String get id_token;
-  external set id_token(String v);
-  external String get login_hint;
-  external set login_hint(String v);
-  external String get scope;
-  external set scope(String v);
-  external num get expires_in;
-  external set expires_in(num v);
-  external num get first_issued_at;
-  external set first_issued_at(num v);
-  external num get expires_at;
-  external set expires_at(num v);
+  external String? get access_token;
+  external set access_token(String? v);
+  external String? get id_token;
+  external set id_token(String? v);
+  external String? get login_hint;
+  external set login_hint(String? v);
+  external String? get scope;
+  external set scope(String? v);
+  external num? get expires_in;
+  external set expires_in(num? v);
+  external num? get first_issued_at;
+  external set first_issued_at(num? v);
+  external num? get expires_at;
+  external set expires_at(num? v);
   external factory AuthResponse(
-      {String access_token,
-      String id_token,
-      String login_hint,
-      String scope,
-      num expires_in,
-      num first_issued_at,
-      num expires_at});
+      {String? access_token,
+      String? id_token,
+      String? login_hint,
+      String? scope,
+      num? expires_in,
+      num? first_issued_at,
+      num? expires_at});
 }
 
 /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authorizeconfig
@@ -282,22 +300,22 @@ abstract class AuthorizeConfig {
   external set client_id(String v);
   external String get scope;
   external set scope(String v);
-  external String get response_type;
-  external set response_type(String v);
-  external String get prompt;
-  external set prompt(String v);
-  external String get cookie_policy;
-  external set cookie_policy(String v);
-  external String get hosted_domain;
-  external set hosted_domain(String v);
-  external String get login_hint;
-  external set login_hint(String v);
-  external String get app_package_name;
-  external set app_package_name(String v);
-  external String get openid_realm;
-  external set openid_realm(String v);
-  external bool get include_granted_scopes;
-  external set include_granted_scopes(bool v);
+  external String? get response_type;
+  external set response_type(String? v);
+  external String? get prompt;
+  external set prompt(String? v);
+  external String? get cookie_policy;
+  external set cookie_policy(String? v);
+  external String? get hosted_domain;
+  external set hosted_domain(String? v);
+  external String? get login_hint;
+  external set login_hint(String? v);
+  external String? get app_package_name;
+  external set app_package_name(String? v);
+  external String? get openid_realm;
+  external set openid_realm(String? v);
+  external bool? get include_granted_scopes;
+  external set include_granted_scopes(bool? v);
   external factory AuthorizeConfig(
       {String client_id,
       String scope,
@@ -350,34 +368,31 @@ abstract class AuthorizeResponse {
 @JS()
 abstract class GoogleUser {
   /// Get the user's unique ID string.
-  external String getId();
+  external String? getId();
 
   /// Returns true if the user is signed in.
   external bool isSignedIn();
 
   /// Get the user's Google Apps domain if the user signed in with a Google Apps account.
-  external String getHostedDomain();
+  external String? getHostedDomain();
 
   /// Get the scopes that the user granted as a space-delimited string.
-  external String getGrantedScopes();
+  external String? getGrantedScopes();
 
   /// Get the user's basic profile information.
-  external BasicProfile getBasicProfile();
+  external BasicProfile? getBasicProfile();
 
   /// Get the response object from the user's auth session.
+  // This returns an empty JS object when the user hasn't attempted to sign in.
   external AuthResponse getAuthResponse([bool includeAuthorizationData]);
 
   /// Returns true if the user granted the specified scopes.
   external bool hasGrantedScopes(String scopes);
 
-  /// Signs in the user. Use this method to request additional scopes for incremental
-  /// authorization or to sign in a user after the user has signed out.
-  /// When you use GoogleUser.signIn(), the sign-in flow skips the account chooser step.
-  /// See GoogleAuth.signIn().
-  external dynamic signIn(
-      [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]);
-
-  /// See GoogleUser.signIn()
+  // Has the API for grant and grantOfflineAccess changed?
+  /// Request additional scopes to the user.
+  ///
+  /// See GoogleAuth.signIn() for the list of parameters and the error code.
   external dynamic grant(
       [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]);
 
@@ -393,35 +408,35 @@ abstract class GoogleUser {
 @anonymous
 @JS()
 abstract class _GoogleUser {
+  /// Forces a refresh of the access token, and then returns a Promise for the new AuthResponse.
   external Promise<AuthResponse> reloadAuthResponse();
 }
 
 extension GoogleUserExtensions on GoogleUser {
   Future<AuthResponse> reloadAuthResponse() {
-    final Object t = this;
-    final _GoogleUser tt = t;
+    final _GoogleUser tt = this as _GoogleUser;
     return promiseToFuture(tt.reloadAuthResponse());
   }
 }
 
 /// Initializes the GoogleAuth object.
 /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2initparams
-@JS("gapi.auth2.init")
+@JS('gapi.auth2.init')
 external GoogleAuth init(ClientConfig params);
 
 /// Returns the GoogleAuth object. You must initialize the GoogleAuth object with gapi.auth2.init() before calling this method.
-@JS("gapi.auth2.getAuthInstance")
-external GoogleAuth getAuthInstance();
+@JS('gapi.auth2.getAuthInstance')
+external GoogleAuth? getAuthInstance();
 
 /// Performs a one time OAuth 2.0 authorization.
 /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authorizeparams-callback
-@JS("gapi.auth2.authorize")
+@JS('gapi.auth2.authorize')
 external void authorize(
     AuthorizeConfig params, void callback(AuthorizeResponse response));
 // End module gapi.auth2
 
 // Module gapi.signin2
-@JS("gapi.signin2.render")
+@JS('gapi.signin2.render')
 external void render(
     dynamic id,
     dynamic
diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart
index f954ff1dce6b..0d3e4165227c 100644
--- a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart
+++ b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart
@@ -20,7 +20,7 @@ external set gapiOnloadCallback(Function callback);
 /// This is only exposed for testing. It shouldn't be accessed by users of the
 /// plugin as it could break at any point.
 @visibleForTesting
-const String kGapiOnloadCallbackFunctionName = "gapiOnloadCallback";
+const String kGapiOnloadCallbackFunctionName = 'gapiOnloadCallback';
 String _addOnloadToScript(String url) => url.startsWith('data:')
     ? url
     : '$url?onload=$kGapiOnloadCallbackFunctionName';
diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart
index 36bb52dce0f3..98cb24efaeeb 100644
--- a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart
+++ b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart
@@ -9,13 +9,22 @@ import 'package:google_sign_in_platform_interface/google_sign_in_platform_interf
 
 import 'generated/gapiauth2.dart' as auth2;
 
-/// Injects a bunch of libraries in the <head> and returns a
-/// Future that resolves when all load.
-Future<void> injectJSLibraries(List<String> libraries,
-    {html.HtmlElement target /*, Duration timeout */}) {
+/// Injects a list of JS [libraries] as `script` tags into a [target] [html.HtmlElement].
+///
+/// If [target] is not provided, it defaults to the web app's `head` tag (see `web/index.html`).
+/// [libraries] is a list of URLs that are used as the `src` attribute of `script` tags
+/// to which an `onLoad` listener is attached (one per URL).
+///
+/// Returns a [Future] that resolves when all of the `script` tags `onLoad` events trigger.
+Future<void> injectJSLibraries(
+  List<String> libraries, {
+  html.HtmlElement? target,
+}) {
   final List<Future<void>> loading = <Future<void>>[];
   final List<html.HtmlElement> tags = <html.HtmlElement>[];
 
+  final html.Element targetElement = target ?? html.querySelector('head')!;
+
   libraries.forEach((String library) {
     final html.ScriptElement script = html.ScriptElement()
       ..async = true
@@ -25,24 +34,26 @@ Future<void> injectJSLibraries(List<String> libraries,
     loading.add(script.onLoad.first);
     tags.add(script);
   });
-  (target ?? html.querySelector('head')).children.addAll(tags);
+
+  targetElement.children.addAll(tags);
   return Future.wait(loading);
 }
 
-/// Utility method that converts `currentUser` to the equivalent
-/// [GoogleSignInUserData].
+/// Utility method that converts `currentUser` to the equivalent [GoogleSignInUserData].
+///
 /// This method returns `null` when the [currentUser] is not signed in.
-GoogleSignInUserData gapiUserToPluginUserData(auth2.GoogleUser currentUser) {
+GoogleSignInUserData? gapiUserToPluginUserData(auth2.GoogleUser? currentUser) {
   final bool isSignedIn = currentUser?.isSignedIn() ?? false;
-  final auth2.BasicProfile profile = currentUser?.getBasicProfile();
+  final auth2.BasicProfile? profile = currentUser?.getBasicProfile();
   if (!isSignedIn || profile?.getId() == null) {
     return null;
   }
+
   return GoogleSignInUserData(
     displayName: profile?.getName(),
-    email: profile?.getEmail(),
-    id: profile?.getId(),
+    email: profile?.getEmail() ?? '',
+    id: profile?.getId() ?? '',
     photoUrl: profile?.getImageUrl(),
-    idToken: currentUser.getAuthResponse()?.id_token,
+    idToken: currentUser?.getAuthResponse().id_token,
   );
 }
diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml
index ac9d36bd15be..ae6807cd9231 100644
--- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml
+++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml
@@ -2,7 +2,7 @@ name: google_sign_in_web
 description: Flutter plugin for Google Sign-In, a secure authentication system
   for signing in with a Google account on Android, iOS and Web.
 homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_web
-version: 0.9.2+1
+version: 0.10.0
 
 flutter:
   plugin:
@@ -12,23 +12,19 @@ flutter:
         fileName: google_sign_in_web.dart
 
 dependencies:
-  google_sign_in_platform_interface: ^1.1.0
+  google_sign_in_platform_interface: ^2.0.0
   flutter:
     sdk: flutter
   flutter_web_plugins:
     sdk: flutter
-  meta: ^1.1.7
-  js: ^0.6.1
+  meta: ^1.3.0
+  js: ^0.6.3
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  google_sign_in: ^4.0.14
-  pedantic: ^1.8.0
-  mockito: ^4.1.1
-  integration_test:
-    path: ../../integration_test
+  pedantic: ^1.10.0
 
 environment:
-  sdk: ">=2.6.0 <3.0.0"
-  flutter: ">=1.12.13+hotfix.4"
+  sdk: ">=2.12.0-259.9.beta <3.0.0"
+  flutter: ">=1.20.0"
diff --git a/packages/google_sign_in/google_sign_in_web/test/README.md b/packages/google_sign_in/google_sign_in_web/test/README.md
index 7c48d024ba57..7c5b4ad682ba 100644
--- a/packages/google_sign_in/google_sign_in_web/test/README.md
+++ b/packages/google_sign_in/google_sign_in_web/test/README.md
@@ -1,17 +1,5 @@
-# Running browser_tests
+## test
 
-Make sure you have updated to the latest Flutter master.
+This package uses integration tests for testing.
 
-1. Check what version of Chrome is running on the machine you're running tests on.
-
-2. Download and install driver for that version from here:
-    * <https://chromedriver.chromium.org/downloads>
-
-3. Start the driver using `chromedriver --port=4444`
-
-4. Change into the `test` directory of your clone.
-
-5. Run tests: `flutter drive -d web-server --browser-name=chrome --target=test_driver/TEST_NAME_integration.dart`, or (in Linux):
-
-    * Single: `./run_test test_driver/TEST_NAME_integration.dart`
-    * All: `./run_test`
+See `example/README.md` for more info.
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart b/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart
deleted file mode 100644
index 39444c0daa24..000000000000
--- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:integration_test/integration_test_driver.dart';
-
-Future<void> main() async => integrationDriver();
diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart b/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart
deleted file mode 100644
index 39444c0daa24..000000000000
--- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:integration_test/integration_test_driver.dart';
-
-Future<void> main() async => integrationDriver();
diff --git a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart
new file mode 100644
index 000000000000..334f52186d9d
--- /dev/null
+++ b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart
@@ -0,0 +1,10 @@
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  test('Tell the user where to find the real tests', () {
+    print('---');
+    print('This package uses integration_test for its tests.');
+    print('See `example/README.md` for more info.');
+    print('---');
+  });
+}