Skip to content

Commit d9d3191

Browse files
authoredJun 24, 2025··
[google_sign_in] Redesign API for current identity SDKs (#9267)
This is a full overhaul of the `google_sign_in` API, with breaking changes for all component packages—including the platform interface. The usual model of adding the new approach while keeping the old one is not viable here, as the underlying SDKs have changed significantly since the original API was designed. Web already had some only-partially-compatible shims for this reason, and Android would have had to do something similar; see flutter/flutter#119300 and flutter/flutter#154205, and [the design doc](https://flutter.dev/go/google-sign-in-authn-authz-updates) for more background. - Fixes flutter/flutter#119300 - Fixes flutter/flutter#154205 - Fixes flutter/flutter#139406 - Fixes flutter/flutter#150365 - Fixes flutter/flutter#137727 - Fixes flutter/flutter#124206 - Fixes flutter/flutter#117794 - Fixes flutter/flutter#107532 - Fixes flutter/flutter#85439 - Fixes flutter/flutter#74308 - Fixes flutter/flutter#71607 - Fixes flutter/flutter#70427 - Fixes flutter/flutter#161890 - Fixes flutter/flutter#157639 - Fixes flutter/flutter#67308 - Fixes flutter/flutter#36673 - Fixes flutter/flutter#32441 (there may be more to do here over time, since we may find exceptions that are not caught, but we now have a structured system to convert errors to as we find specific unhandled cases) ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent d848b16 commit d9d3191

21 files changed

+1504
-1173
lines changed
 

‎packages/google_sign_in/google_sign_in/CHANGELOG.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
## NEXT
2-
3-
* Updates README to indicate that Andoid SDK <21 is no longer supported.
1+
## 7.0.0
2+
3+
* **BREAKING CHANGE**: Many APIs have changed or been replaced to reflect the
4+
current APIs and best practices of the underlying platform SDKs. For full
5+
details, see the README and migration guide, but notable highlights include:
6+
* The `GoogleSignIn` instance is now a singleton.
7+
* Clients must call and await the new `initialize` method before calling any
8+
other methods on the instance.
9+
* Authentication and authorization are now separate steps.
10+
* Access tokens and server auth codes are obtained via separate calls.
411

512
## 6.3.0
613

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Migrating from `google_sign_in` 6.x to 7.x
2+
3+
The API of `google_sign_in` 6.x and earlier was designed for the Google Sign-In
4+
SDK, which has been deprecated on both Android and Web, and replaced with new
5+
SDKs that have significantly different structures. As a result, the
6+
`google_sign_in` API surface has changed significantly. Notable differences
7+
include:
8+
* `GoogleSignIn` is now a singleton, which is obtained via
9+
`GoogleSignIn.instance`. In practice, creating multiple `GoogleSignIn`
10+
instances in 6.x would not work correctly, so this just enforces an existing
11+
restriction.
12+
* There is now an explicit `initialize` step that must be called exactly once,
13+
before any other methods. On some platforms the future will complete almost
14+
immediately, but on others (for example, web) it may take some time.
15+
* The plugin no longer tracks a single "current" signed in user. Instead,
16+
applications that assume a single signed in user should track this at the
17+
application level using the `authenticationEvents` stream.
18+
* Authentication (signing in) and authorization (allowing access to user data
19+
in the form of scopes) are now separate steps. Recommended practice is to
20+
authenticate as soon as it makes sense for a user to potentially be signed in,
21+
but to delay authorization until the point where the data will actually be
22+
used.
23+
* In applications where these steps should happen at the same time, you can
24+
pass a `scopeHint` during the authentication step. On platforms that support
25+
it this allows for a combined authentication and authorization UI flow.
26+
Not all platforms allow combining these flows, so your application should be
27+
prepared to trigger a separate authorization prompt if necessary.
28+
* Authorization is further separated into client and server authorization.
29+
Applications that need a `serverAuthCode` must now call a separate method,
30+
`authorizeServer`, to obtain that code.
31+
* Client authorization is handled via two new methods:
32+
* `authorizationForScopes`, which returns an access token if the requested
33+
scopes are already authorized, or null if not, and
34+
* `authorizeScopes`, which requests that the user authorize the scopes, and
35+
is expected to show UI.
36+
37+
Clients should generally attempt to get tokens via `authorizationForScopes`,
38+
and if they are unable to do so, show some UI to request authoriaztion that
39+
calls `authorizeScopes`. This is similar to the previously web-only flow
40+
of calling `canAccessScopes` and then calling `addScopes` if necessary.
41+
* `signInSilently` has been replaced with `attemptLightweightAuthentication`.
42+
The intended usage is essentially the same, but the change reflects that it
43+
is no longer guaranteed to be silent. For example, as of the publishing of
44+
7.0, on web this may show a floating sign-in card, and on Android it may show
45+
an account selection sheet.
46+
* This new method is no longer guaranteed to return a future. This allows
47+
clients to distinguish, at runtime:
48+
* platforms where a definitive "signed in" or "not signed in" response
49+
can be returned quickly, and thus `await`-ing completion is reasonable,
50+
in which case a `Future` is returned, and
51+
* platforms (such as web) where it could take an arbitrary amount of time,
52+
in which case no `Future` is returned, and clients should assume a
53+
non-signed-in state until/unless a sign-in event is eventually posted to
54+
the `authenticationEvents` stream.
55+
* `authenticate` replaces the authentication portion of `signIn` on platforms
56+
that support it (see below).
57+
* The new `supportsAuthenticate` method allows clients to determine at runtime
58+
whether the `authenticate` method is supported, as some platforms do not allow
59+
custom UI to trigger explicit authentication. These platforms instead provide
60+
some other platform-specific way of triggering authentication. As of
61+
publishing, the only platform that does not support `authenticate` is web,
62+
where `google_sign_in_web`'s `renderButton` is used to create a sign-in
63+
button.

‎packages/google_sign_in/google_sign_in/README.md

Lines changed: 94 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -6,182 +6,145 @@ A Flutter plugin for [Google Sign In](https://developers.google.com/identity/).
66
|-------------|---------|-------|--------|-----|
77
| **Support** | SDK 21+ | 12.0+ | 10.15+ | Any |
88

9-
## Platform integration
9+
## Setup
1010

11-
### Android integration
12-
13-
To access Google Sign-In, you'll need to make sure to
14-
[register your application](https://firebase.google.com/docs/android/setup).
15-
16-
You don't need to include the google-services.json file in your app unless you
17-
are using Google services that require it. You do need to enable the OAuth APIs
18-
that you want, using the
19-
[Google Cloud Platform API manager](https://console.developers.google.com/). For
20-
example, if you want to mimic the behavior of the Google Sign-In sample app,
21-
you'll need to enable the
22-
[Google People API](https://developers.google.com/people/).
23-
24-
Make sure you've filled out all required fields in the console for
25-
[OAuth consent screen](https://console.developers.google.com/apis/credentials/consent).
26-
Otherwise, you may encounter `APIException` errors.
27-
28-
### iOS integration
29-
30-
Please see [instructions on integrating Google Sign-In for iOS](https://pub.dev/packages/google_sign_in_ios#ios-integration).
31-
32-
#### iOS additional requirement
33-
34-
Note that according to
35-
https://developer.apple.com/sign-in-with-apple/get-started, starting June 30,
36-
2020, apps that use login services must also offer a "Sign in with Apple" option
37-
when submitting to the Apple App Store.
38-
39-
Consider also using an Apple sign in plugin from pub.dev.
40-
41-
The Flutter Favorite
42-
[sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) plugin could
43-
be an option.
44-
45-
### macOS integration
46-
47-
Please see [instructions on integrating Google Sign-In for macOS](https://pub.dev/packages/google_sign_in_ios#macos-setup).
48-
49-
### Web integration
11+
### Import the package
5012

51-
The new SDK used by the web has fully separated Authentication from Authorization,
52-
so `signIn` and `signInSilently` no longer authorize OAuth `scopes`.
13+
To use this plugin, follow the
14+
[plugin installation instructions](https://pub.dev/packages/google_sign_in/install),
15+
then follow the platform integration steps below for all platforms you support.
5316

54-
Flutter apps must be able to detect what scopes have been granted by their users,
55-
and if the grants are still valid.
17+
### Platform integration
5618

57-
Read below about **Working with scopes, and incremental authorization** for
58-
general information about changes that may be needed on an app, and for more
59-
specific web integration details, see the
60-
[`google_sign_in_web` package](https://pub.dev/packages/google_sign_in_web).
19+
* **Android**: Please see [the `google_sign_in_android` README](https://pub.dev/packages/google_sign_in_android#integration).
20+
* **iOS**: Please see [the `google_sign_in_ios` README](https://pub.dev/packages/google_sign_in_ios#ios-integration).
21+
* **macOS**: Please see [the `google_sign_in_ios` README](https://pub.dev/packages/google_sign_in_ios#macos-integration) (which also supports macOS).
22+
* **Web**: Please see [the `google_sign_in_web` README](https://pub.dev/packages/google_sign_in_web#integration).
6123

6224
## Usage
6325

64-
### Import the package
26+
### Initialization and authentication
6527

66-
To use this plugin, follow the
67-
[plugin installation instructions](https://pub.dev/packages/google_sign_in/install).
28+
Initialize the `GoogleSignIn` instance, and (optionally) start the lightweight
29+
authentication process:
6830

69-
### Use the plugin
70-
71-
Initialize `GoogleSignIn` with the scopes you want:
72-
73-
<?code-excerpt "example/lib/main.dart (Initialize)"?>
31+
<?code-excerpt "example/lib/main.dart (Setup)"?>
7432
```dart
75-
const List<String> scopes = <String>[
76-
'email',
77-
'https://www.googleapis.com/auth/contacts.readonly',
78-
];
79-
80-
GoogleSignIn _googleSignIn = GoogleSignIn(
81-
// Optional clientId
82-
// clientId: 'your-client_id.apps.googleusercontent.com',
83-
scopes: scopes,
84-
);
33+
final GoogleSignIn signIn = GoogleSignIn.instance;
34+
unawaited(signIn
35+
.initialize(clientId: clientId, serverClientId: serverClientId)
36+
.then((_) {
37+
signIn.authenticationEvents
38+
.listen(_handleAuthenticationEvent)
39+
.onError(_handleAuthenticationError);
40+
41+
/// This example always uses the stream-based approach to determining
42+
/// which UI state to show, rather than using the future returned here,
43+
/// if any, to conditionally skip directly to the signed-in state.
44+
signIn.attemptLightweightAuthentication();
45+
}));
8546
```
8647

87-
[Full list of available scopes](https://developers.google.com/identity/protocols/googlescopes).
88-
89-
You can now use the `GoogleSignIn` class to authenticate in your Dart code, e.g.
48+
If the user isn't signed in by the lightweight method, you can show UI to
49+
start a sign-in flow. This uses `authenticate` on platforms that return true
50+
for `supportsAuthenticate`, otherwise applications should fall back to a
51+
platform-specific approach. For instance, user-initiated sign in on web must
52+
use a button rendered by the sign in SDK, rather than application-provided
53+
UI:
9054

91-
<?code-excerpt "example/lib/main.dart (SignIn)"?>
55+
<?code-excerpt "example/lib/main.dart (ExplicitSignIn)"?>
9256
```dart
93-
Future<void> _handleSignIn() async {
94-
try {
95-
await _googleSignIn.signIn();
96-
} catch (error) {
97-
print(error);
98-
}
99-
}
57+
if (GoogleSignIn.instance.supportsAuthenticate())
58+
ElevatedButton(
59+
onPressed: () async {
60+
try {
61+
await GoogleSignIn.instance.authenticate();
62+
} catch (e) {
63+
// ···
64+
}
65+
},
66+
child: const Text('SIGN IN'),
67+
)
68+
else ...<Widget>[
69+
if (kIsWeb)
70+
web.renderButton()
71+
// ···
72+
]
10073
```
10174

102-
In the web, you should use the **Google Sign In button** (and not the `signIn` method)
103-
to guarantee that your user authentication contains a valid `idToken`.
104-
105-
For more details, take a look at the
106-
[`google_sign_in_web` package](https://pub.dev/packages/google_sign_in_web).
107-
108-
## Working with scopes, and incremental authorization.
109-
110-
If your app supports both mobile and web, read this section!
75+
## Authorization
11176

11277
### Checking if scopes have been granted
11378

114-
Users may (or may *not*) grant all the scopes that an application requests at
115-
Sign In. In fact, in the web, no scopes are granted by `signIn`, `silentSignIn`
116-
or the `renderButton` widget anymore.
117-
118-
Applications must be able to:
119-
120-
* Detect if the authenticated user has authorized the scopes they need.
121-
* Determine if the scopes that were granted a few minutes ago are still valid.
122-
123-
There's a new method that enables the checks above, `canAccessScopes`:
79+
If the user has previously authorized the scopes required by your application,
80+
you can silently request an access token for those scopes:
12481

125-
<?code-excerpt "example/lib/main.dart (CanAccessScopes)"?>
82+
<?code-excerpt "example/lib/main.dart (CheckAuthorization)" plaster="none"?>
12683
```dart
127-
// In mobile, being authenticated means being authorized...
128-
bool isAuthorized = account != null;
129-
// However, on web...
130-
if (kIsWeb && account != null) {
131-
isAuthorized = await _googleSignIn.canAccessScopes(scopes);
132-
}
84+
const List<String> scopes = <String>[
85+
'https://www.googleapis.com/auth/contacts.readonly',
86+
];
87+
final GoogleSignInAccount? user = // ...
88+
final GoogleSignInClientAuthorization? authorization =
89+
await user?.authorizationClient.authorizationForScopes(scopes);
13390
```
13491

135-
_(Only implemented in the web platform, from version 6.1.0 of this package)_
92+
[Full list of available scopes](https://developers.google.com/identity/protocols/googlescopes).
13693

13794
### Requesting more scopes when needed
13895

13996
If an app determines that the user hasn't granted the scopes it requires, it
140-
should initiate an Authorization request. (Remember that in the web platform,
141-
this request **must be initiated from an user interaction**, like a button press).
97+
should initiate an Authorization request. On platforms where
98+
`authorizationRequiresUserInteraction()` returns true,
99+
this request **must be initiated from a user interaction** like a button press.
142100

143-
<?code-excerpt "example/lib/main.dart (RequestScopes)" plaster="none"?>
101+
<?code-excerpt "example/lib/main.dart (RequestScopes)"?>
144102
```dart
145-
Future<void> _handleAuthorizeScopes() async {
146-
final bool isAuthorized = await _googleSignIn.requestScopes(scopes);
147-
if (isAuthorized) {
148-
unawaited(_handleGetContact(_currentUser!));
149-
}
103+
final GoogleSignInClientAuthorization authorization =
104+
await user.authorizationClient.authorizeScopes(scopes);
150105
```
151106

152-
The `requestScopes` returns a `boolean` value that is `true` if the user has
153-
granted all the requested scopes or `false` otherwise.
154-
155-
Once your app determines that the current user `isAuthorized` to access the
156-
services for which you need `scopes`, it can proceed normally.
157-
158107
### Authorization expiration
159108

160109
In the web, **the `accessToken` is no longer refreshed**. It expires after 3600
161110
seconds (one hour), so your app needs to be able to handle failed REST requests,
162111
and update its UI to prompt the user for a new Authorization round.
163112

164113
This can be done by combining the error responses from your REST requests with
165-
the `canAccessScopes` and `requestScopes` methods described above.
114+
the authorization methods described above.
166115

167116
For more details, take a look at the
168117
[`google_sign_in_web` package](https://pub.dev/packages/google_sign_in_web).
169118

170-
### Does an app always need to check `canAccessScopes`?
119+
### Requesting a server auth code
171120

172-
The new web SDK implicitly grant access to the `email`, `profile` and `openid`
173-
scopes when users complete the sign-in process (either via the One Tap UX or the
174-
Google Sign In button).
121+
If your application needs to access user data from a backend server, you can
122+
request a server auth code to send to the server:
175123

176-
If an app only needs an `idToken`, or only requests permissions to any/all of
177-
the three scopes mentioned above
178-
([OpenID Connect scopes](https://developers.google.com/identity/protocols/oauth2/scopes#openid-connect)),
179-
it won't need to implement any additional scope handling.
124+
<?code-excerpt "example/lib/main.dart (RequestServerAuth)"?>
125+
```dart
126+
final GoogleSignInServerAuthorization? serverAuth =
127+
await user.authorizationClient.authorizeServer(scopes);
128+
```
129+
130+
Server auth codes are not always available on all platforms. For instance, on
131+
some platforms they may only be returned when a user initially signs in, and
132+
not for subsequent authentications via the lightweight process. If you
133+
need a server auth code you should request it as soon as possible after initial
134+
sign-in, and manage server tokens for that user entirely on the server side
135+
unless the signed in user changes.
180136

181-
If an app needs any scope other than `email`, `profile` and `openid`, it **must**
182-
implement a more complete scope handling, as described above.
137+
On platforms where `authorizationRequiresUserInteraction()` returns true,
138+
this request **must be initiated from a user interaction** like a button press.
183139

184140
## Example
185141

186-
Find the example wiring in the
187-
[Google sign-in example application](https://github.com/flutter/packages/blob/main/packages/google_sign_in/google_sign_in/example/lib/main.dart).
142+
The
143+
[Google Sign-In example application](https://github.com/flutter/packages/blob/main/packages/google_sign_in/google_sign_in/example/lib/main.dart) demonstrates one approach to using this
144+
package to sign a user in and authorize access to specific user data.
145+
146+
## Migration from pre-7.0 versions
147+
148+
If you used version 6.x or earlier of `google_sign_in`, see
149+
[the migration guide](https://github.com/flutter/packages/blob/main/packages/google_sign_in/google_sign_in/MIGRATION.md)
150+
for more information about the changes.

‎packages/google_sign_in/google_sign_in/example/integration_test/google_sign_in_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ void main() {
1010
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
1111

1212
testWidgets('Can initialize the plugin', (WidgetTester tester) async {
13-
final GoogleSignIn signIn = GoogleSignIn();
13+
final GoogleSignIn signIn = GoogleSignIn.instance;
1414
expect(signIn, isNotNull);
15+
16+
await signIn.initialize();
1517
});
1618
}

‎packages/google_sign_in/google_sign_in/example/lib/main.dart

Lines changed: 214 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,22 @@ import 'package:flutter/material.dart';
1212
import 'package:google_sign_in/google_sign_in.dart';
1313
import 'package:http/http.dart' as http;
1414

15-
import 'src/sign_in_button.dart';
15+
import 'src/web_wrapper.dart' as web;
16+
17+
/// To run this example, replace this value with your client ID, and/or
18+
/// update the relevant configuration files, as described in the README.
19+
String? clientId;
20+
21+
/// To run this example, replace this value with your server client ID, and/or
22+
/// update the relevant configuration files, as described in the README.
23+
String? serverClientId;
1624

1725
/// The scopes required by this application.
18-
// #docregion Initialize
26+
// #docregion CheckAuthorization
1927
const List<String> scopes = <String>[
20-
'email',
2128
'https://www.googleapis.com/auth/contacts.readonly',
2229
];
23-
24-
GoogleSignIn _googleSignIn = GoogleSignIn(
25-
// Optional clientId
26-
// clientId: 'your-client_id.apps.googleusercontent.com',
27-
scopes: scopes,
28-
);
29-
// #enddocregion Initialize
30+
// #enddocregion CheckAuthorization
3031

3132
void main() {
3233
runApp(
@@ -50,58 +51,102 @@ class _SignInDemoState extends State<SignInDemo> {
5051
GoogleSignInAccount? _currentUser;
5152
bool _isAuthorized = false; // has granted permissions?
5253
String _contactText = '';
54+
String _errorMessage = '';
55+
String _serverAuthCode = '';
5356

5457
@override
5558
void initState() {
5659
super.initState();
5760

58-
_googleSignIn.onCurrentUserChanged
59-
.listen((GoogleSignInAccount? account) async {
60-
// #docregion CanAccessScopes
61-
// In mobile, being authenticated means being authorized...
62-
bool isAuthorized = account != null;
63-
// However, on web...
64-
if (kIsWeb && account != null) {
65-
isAuthorized = await _googleSignIn.canAccessScopes(scopes);
66-
}
67-
// #enddocregion CanAccessScopes
61+
// #docregion Setup
62+
final GoogleSignIn signIn = GoogleSignIn.instance;
63+
unawaited(signIn
64+
.initialize(clientId: clientId, serverClientId: serverClientId)
65+
.then((_) {
66+
signIn.authenticationEvents
67+
.listen(_handleAuthenticationEvent)
68+
.onError(_handleAuthenticationError);
6869

69-
setState(() {
70-
_currentUser = account;
71-
_isAuthorized = isAuthorized;
72-
});
70+
/// This example always uses the stream-based approach to determining
71+
/// which UI state to show, rather than using the future returned here,
72+
/// if any, to conditionally skip directly to the signed-in state.
73+
signIn.attemptLightweightAuthentication();
74+
}));
75+
// #enddocregion Setup
76+
}
7377

74-
// Now that we know that the user can access the required scopes, the app
75-
// can call the REST API.
76-
if (isAuthorized) {
77-
unawaited(_handleGetContact(account!));
78-
}
78+
Future<void> _handleAuthenticationEvent(
79+
GoogleSignInAuthenticationEvent event) async {
80+
// #docregion CheckAuthorization
81+
final GoogleSignInAccount? user = // ...
82+
// #enddocregion CheckAuthorization
83+
switch (event) {
84+
GoogleSignInAuthenticationEventSignIn() => event.user,
85+
GoogleSignInAuthenticationEventSignOut() => null,
86+
};
87+
88+
// Check for existing authorization.
89+
// #docregion CheckAuthorization
90+
final GoogleSignInClientAuthorization? authorization =
91+
await user?.authorizationClient.authorizationForScopes(scopes);
92+
// #enddocregion CheckAuthorization
93+
94+
setState(() {
95+
_currentUser = user;
96+
_isAuthorized = authorization != null;
97+
_errorMessage = '';
7998
});
8099

81-
// In the web, _googleSignIn.signInSilently() triggers the One Tap UX.
82-
//
83-
// It is recommended by Google Identity Services to render both the One Tap UX
84-
// and the Google Sign In button together to "reduce friction and improve
85-
// sign-in rates" ([docs](https://developers.google.com/identity/gsi/web/guides/display-button#html)).
86-
_googleSignIn.signInSilently();
100+
// If the user has already granted access to the required scopes, call the
101+
// REST API.
102+
if (user != null && authorization != null) {
103+
unawaited(_handleGetContact(user));
104+
}
105+
}
106+
107+
Future<void> _handleAuthenticationError(Object e) async {
108+
setState(() {
109+
_currentUser = null;
110+
_isAuthorized = false;
111+
_errorMessage = e is GoogleSignInException
112+
? 'GoogleSignInException ${e.code}: ${e.description}'
113+
: 'Unknown error: $e';
114+
});
87115
}
88116

89117
// Calls the People API REST endpoint for the signed-in user to retrieve information.
90118
Future<void> _handleGetContact(GoogleSignInAccount user) async {
91119
setState(() {
92120
_contactText = 'Loading contact info...';
93121
});
122+
final Map<String, String>? headers =
123+
await user.authorizationClient.authorizationHeaders(scopes);
124+
if (headers == null) {
125+
setState(() {
126+
_contactText = '';
127+
_errorMessage = 'Failed to construct authorization headers.';
128+
});
129+
return;
130+
}
94131
final http.Response response = await http.get(
95132
Uri.parse('https://people.googleapis.com/v1/people/me/connections'
96133
'?requestMask.includeField=person.names'),
97-
headers: await user.authHeaders,
134+
headers: headers,
98135
);
99136
if (response.statusCode != 200) {
100-
setState(() {
101-
_contactText = 'People API gave a ${response.statusCode} '
102-
'response. Check logs for details.';
103-
});
104-
print('People API ${response.statusCode} response: ${response.body}');
137+
if (response.statusCode == 401 || response.statusCode == 403) {
138+
setState(() {
139+
_isAuthorized = false;
140+
_errorMessage = 'People API gave a ${response.statusCode} response. '
141+
'Please re-authorize access.';
142+
});
143+
} else {
144+
print('People API ${response.statusCode} response: ${response.body}');
145+
setState(() {
146+
_contactText = 'People API gave a ${response.statusCode} '
147+
'response. Check logs for details.';
148+
});
149+
}
105150
return;
106151
}
107152
final Map<String, dynamic> data =
@@ -136,94 +181,147 @@ class _SignInDemoState extends State<SignInDemo> {
136181
return null;
137182
}
138183

139-
// This is the on-click handler for the Sign In button that is rendered by Flutter.
184+
// Prompts the user to authorize `scopes`.
140185
//
141-
// On the web, the on-click handler of the Sign In button is owned by the JS
142-
// SDK, so this method can be considered mobile only.
143-
// #docregion SignIn
144-
Future<void> _handleSignIn() async {
186+
// If authorizationRequiresUserInteraction() is true, this must be called from
187+
// a user interaction (button click). In this example app, a button is used
188+
// regardless, so authorizationRequiresUserInteraction() is not checked.
189+
Future<void> _handleAuthorizeScopes(GoogleSignInAccount user) async {
145190
try {
146-
await _googleSignIn.signIn();
147-
} catch (error) {
148-
print(error);
191+
// #docregion RequestScopes
192+
final GoogleSignInClientAuthorization authorization =
193+
await user.authorizationClient.authorizeScopes(scopes);
194+
// #enddocregion RequestScopes
195+
196+
// The returned tokens are ignored since _handleGetContact uses the
197+
// authorizationHeaders method to re-read the token cached by
198+
// authorizeScopes. The code above is used as a README excerpt, so shows
199+
// the simpler pattern of getting the authorization for immediate use.
200+
// That results in an unused variable, which this statement suppresses
201+
// (without adding an ignore: directive to the README excerpt).
202+
// ignore: unnecessary_statements
203+
authorization;
204+
205+
setState(() {
206+
_isAuthorized = true;
207+
_errorMessage = '';
208+
});
209+
unawaited(_handleGetContact(_currentUser!));
210+
} on GoogleSignInException catch (e) {
211+
_errorMessage = 'GoogleSignInException ${e.code}: ${e.description}';
149212
}
150213
}
151-
// #enddocregion SignIn
152214

153-
// Prompts the user to authorize `scopes`.
215+
// Requests a server auth code for the authorized scopes.
154216
//
155-
// This action is **required** in platforms that don't perform Authentication
156-
// and Authorization at the same time (like the web).
157-
//
158-
// On the web, this must be called from an user interaction (button click).
159-
// #docregion RequestScopes
160-
Future<void> _handleAuthorizeScopes() async {
161-
final bool isAuthorized = await _googleSignIn.requestScopes(scopes);
162-
// #enddocregion RequestScopes
163-
setState(() {
164-
_isAuthorized = isAuthorized;
165-
});
166-
// #docregion RequestScopes
167-
if (isAuthorized) {
168-
unawaited(_handleGetContact(_currentUser!));
217+
// If authorizationRequiresUserInteraction() is true, this must be called from
218+
// a user interaction (button click). In this example app, a button is used
219+
// regardless, so authorizationRequiresUserInteraction() is not checked.
220+
Future<void> _handleGetAuthCode(GoogleSignInAccount user) async {
221+
try {
222+
// #docregion RequestServerAuth
223+
final GoogleSignInServerAuthorization? serverAuth =
224+
await user.authorizationClient.authorizeServer(scopes);
225+
// #enddocregion RequestServerAuth
226+
227+
setState(() {
228+
_serverAuthCode = serverAuth == null ? '' : serverAuth.serverAuthCode;
229+
});
230+
} on GoogleSignInException catch (e) {
231+
_errorMessage = 'GoogleSignInException ${e.code}: ${e.description}';
169232
}
170-
// #enddocregion RequestScopes
171233
}
172234

173-
Future<void> _handleSignOut() => _googleSignIn.disconnect();
235+
Future<void> _handleSignOut() async {
236+
// Disconnect instead of just signing out, to reset the example state as
237+
// much as possible.
238+
await GoogleSignIn.instance.disconnect();
239+
}
174240

175241
Widget _buildBody() {
176242
final GoogleSignInAccount? user = _currentUser;
177-
if (user != null) {
178-
// The user is Authenticated
179-
return Column(
180-
mainAxisAlignment: MainAxisAlignment.spaceAround,
181-
children: <Widget>[
182-
ListTile(
183-
leading: GoogleUserCircleAvatar(
184-
identity: user,
185-
),
186-
title: Text(user.displayName ?? ''),
187-
subtitle: Text(user.email),
188-
),
189-
const Text('Signed in successfully.'),
190-
if (_isAuthorized) ...<Widget>[
191-
// The user has Authorized all required scopes
192-
Text(_contactText),
193-
ElevatedButton(
194-
child: const Text('REFRESH'),
195-
onPressed: () => _handleGetContact(user),
196-
),
197-
],
198-
if (!_isAuthorized) ...<Widget>[
199-
// The user has NOT Authorized all required scopes.
200-
// (Mobile users may never see this button!)
201-
const Text('Additional permissions needed to read your contacts.'),
202-
ElevatedButton(
203-
onPressed: _handleAuthorizeScopes,
204-
child: const Text('REQUEST PERMISSIONS'),
205-
),
206-
],
243+
return Column(
244+
mainAxisAlignment: MainAxisAlignment.spaceAround,
245+
children: <Widget>[
246+
if (user != null)
247+
..._buildAuthenticatedWidgets(user)
248+
else
249+
..._buildUnauthenticatedWidgets(),
250+
if (_errorMessage.isNotEmpty) Text(_errorMessage),
251+
],
252+
);
253+
}
254+
255+
/// Returns the list of widgets to include if the user is authenticated.
256+
List<Widget> _buildAuthenticatedWidgets(GoogleSignInAccount user) {
257+
return <Widget>[
258+
// The user is Authenticated.
259+
ListTile(
260+
leading: GoogleUserCircleAvatar(
261+
identity: user,
262+
),
263+
title: Text(user.displayName ?? ''),
264+
subtitle: Text(user.email),
265+
),
266+
const Text('Signed in successfully.'),
267+
if (_isAuthorized) ...<Widget>[
268+
// The user has Authorized all required scopes.
269+
if (_contactText.isNotEmpty) Text(_contactText),
270+
ElevatedButton(
271+
child: const Text('REFRESH'),
272+
onPressed: () => _handleGetContact(user),
273+
),
274+
if (_serverAuthCode.isEmpty)
207275
ElevatedButton(
208-
onPressed: _handleSignOut,
209-
child: const Text('SIGN OUT'),
210-
),
211-
],
212-
);
213-
} else {
214-
// The user is NOT Authenticated
215-
return Column(
216-
mainAxisAlignment: MainAxisAlignment.spaceAround,
217-
children: <Widget>[
218-
const Text('You are not currently signed in.'),
219-
// This method is used to separate mobile from web code with conditional exports.
220-
// See: src/sign_in_button.dart
221-
buildSignInButton(
222-
onPressed: _handleSignIn,
223-
),
224-
],
225-
);
226-
}
276+
child: const Text('REQUEST SERVER CODE'),
277+
onPressed: () => _handleGetAuthCode(user),
278+
)
279+
else
280+
Text('Server auth code:\n$_serverAuthCode'),
281+
] else ...<Widget>[
282+
// The user has NOT Authorized all required scopes.
283+
const Text('Authorization needed to read your contacts.'),
284+
ElevatedButton(
285+
onPressed: () => _handleAuthorizeScopes(user),
286+
child: const Text('REQUEST PERMISSIONS'),
287+
),
288+
],
289+
ElevatedButton(
290+
onPressed: _handleSignOut,
291+
child: const Text('SIGN OUT'),
292+
),
293+
];
294+
}
295+
296+
/// Returns the list of widgets to include if the user is not authenticated.
297+
List<Widget> _buildUnauthenticatedWidgets() {
298+
return <Widget>[
299+
const Text('You are not currently signed in.'),
300+
// #docregion ExplicitSignIn
301+
if (GoogleSignIn.instance.supportsAuthenticate())
302+
ElevatedButton(
303+
onPressed: () async {
304+
try {
305+
await GoogleSignIn.instance.authenticate();
306+
} catch (e) {
307+
// #enddocregion ExplicitSignIn
308+
_errorMessage = e.toString();
309+
// #docregion ExplicitSignIn
310+
}
311+
},
312+
child: const Text('SIGN IN'),
313+
)
314+
else ...<Widget>[
315+
if (kIsWeb)
316+
web.renderButton()
317+
// #enddocregion ExplicitSignIn
318+
else
319+
const Text(
320+
'This platform does not have a known authentication method')
321+
// #docregion ExplicitSignIn
322+
]
323+
// #enddocregion ExplicitSignIn
324+
];
227325
}
228326

229327
@override

‎packages/google_sign_in/google_sign_in/example/lib/src/sign_in_button/mobile.dart

Lines changed: 0 additions & 15 deletions
This file was deleted.

‎packages/google_sign_in/google_sign_in/example/lib/src/sign_in_button/stub.dart

Lines changed: 0 additions & 15 deletions
This file was deleted.

‎packages/google_sign_in/google_sign_in/example/lib/src/sign_in_button.dart renamed to ‎packages/google_sign_in/google_sign_in/example/lib/src/web_wrapper.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,4 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
export 'sign_in_button/stub.dart'
6-
if (dart.library.js_util) 'sign_in_button/web.dart'
7-
if (dart.library.io) 'sign_in_button/mobile.dart';
5+
export 'web_wrapper_stub.dart' if (dart.library.js_util) 'web_wrapper_web.dart';

‎packages/google_sign_in/google_sign_in/example/lib/src/sign_in_button/web.dart renamed to ‎packages/google_sign_in/google_sign_in/example/lib/src/web_wrapper_stub.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
// found in the LICENSE file.
44

55
import 'package:flutter/material.dart';
6-
import 'package:google_sign_in_web/web_only.dart' as web;
76

8-
import 'stub.dart';
9-
10-
/// Renders a web-only SIGN IN button.
11-
Widget buildSignInButton({HandleSignInFn? onPressed}) {
12-
return web.renderButton();
7+
/// Stub for the web-only renderButton method, since google_sign_in_web has to
8+
/// be behind a conditional import.
9+
Widget renderButton() {
10+
throw StateError('This should only be called on web');
1311
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
export 'package:google_sign_in_web/web_only.dart';

‎packages/google_sign_in/google_sign_in/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies:
1616
# The example app is bundled with the plugin so we use a path dependency on
1717
# the parent directory to use the current plugin's version.
1818
path: ../
19-
google_sign_in_web: ^0.12.3
19+
google_sign_in_web: ^1.0.0
2020
http: ">=0.13.0 <2.0.0"
2121

2222
dev_dependencies:

‎packages/google_sign_in/google_sign_in/lib/google_sign_in.dart

Lines changed: 413 additions & 355 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/foundation.dart';
6+
7+
import '../google_sign_in.dart';
8+
9+
export 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'
10+
show GoogleSignInException;
11+
12+
/// A base class for authentication event streams.
13+
@immutable
14+
sealed class GoogleSignInAuthenticationEvent {
15+
const GoogleSignInAuthenticationEvent();
16+
}
17+
18+
/// A sign-in event, corresponding to an authentication flow completing
19+
/// successfully.
20+
@immutable
21+
class GoogleSignInAuthenticationEventSignIn
22+
extends GoogleSignInAuthenticationEvent {
23+
/// Creates an event for a successful sign in.
24+
const GoogleSignInAuthenticationEventSignIn({required this.user});
25+
26+
/// The user that was authenticated.
27+
final GoogleSignInAccount user;
28+
}
29+
30+
/// A sign-out event, corresponding to a user having been signed out.
31+
///
32+
/// Implicit sign-outs (for example, due to server-side authentication
33+
/// revocation, or timeouts) are not guaranteed to send events.
34+
@immutable
35+
class GoogleSignInAuthenticationEventSignOut
36+
extends GoogleSignInAuthenticationEvent {}

‎packages/google_sign_in/google_sign_in/lib/src/common.dart renamed to ‎packages/google_sign_in/google_sign_in/lib/src/identity_types.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,4 @@ abstract class GoogleIdentity {
3434
///
3535
/// Not guaranteed to be present for all users, even when configured.
3636
String? get photoUrl;
37-
38-
/// Server auth code used to access Google Login
39-
String? get serverAuthCode;
4037
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/foundation.dart';
6+
7+
/// Holds authentication tokens.
8+
///
9+
/// Currently there is only an idToken, but this wrapper class allows for the
10+
/// posibility of adding additional information in the future without breaking
11+
/// changes.
12+
@immutable
13+
class GoogleSignInAuthentication {
14+
/// Creates a new token container with the given tokens.
15+
const GoogleSignInAuthentication({required this.idToken});
16+
17+
/// An OpenID Connect ID token that identifies the user.
18+
final String? idToken;
19+
20+
@override
21+
String toString() => 'GoogleSignInAuthentication: $idToken';
22+
}
23+
24+
/// Holds client authorization tokens.
25+
///
26+
/// Currently there is only an accessToken, but this wrapper class allows for
27+
/// the posibility of adding additional information in the future without
28+
/// breaking changes.
29+
@immutable
30+
class GoogleSignInClientAuthorization {
31+
/// Creates a new token container with the given tokens.
32+
const GoogleSignInClientAuthorization({required this.accessToken});
33+
34+
/// The OAuth2 access token to access Google services.
35+
final String accessToken;
36+
37+
@override
38+
String toString() => 'GoogleSignInClientAuthorization: $accessToken';
39+
}
40+
41+
/// Holds server authorization tokens.
42+
///
43+
/// Currently there is only a serverAuthCode, but this wrapper class allows for
44+
/// the posibility of adding additional information in the future without
45+
/// breaking changes.
46+
@immutable
47+
class GoogleSignInServerAuthorization {
48+
/// Creates a new token container with the given tokens.
49+
const GoogleSignInServerAuthorization({required this.serverAuthCode});
50+
51+
/// Auth code to provide to a backend server to exchange for access or
52+
/// refresh tokens.
53+
final String serverAuthCode;
54+
55+
@override
56+
String toString() => 'GoogleSignInServerAuthorization: $serverAuthCode';
57+
}

‎packages/google_sign_in/google_sign_in/lib/widgets.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import 'dart:typed_data';
66

77
import 'package:flutter/material.dart';
88

9-
import 'src/common.dart';
109
import 'src/fife.dart' as fife;
10+
import 'src/identity_types.dart';
1111

1212
/// Builds a CircleAvatar profile image of the appropriate resolution
1313
class GoogleUserCircleAvatar extends StatelessWidget {

‎packages/google_sign_in/google_sign_in/pubspec.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
33
for signing in with a Google account.
44
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
6-
version: 6.3.0
6+
version: 7.0.0
77

88
environment:
99
sdk: ^3.6.0
@@ -24,17 +24,18 @@ flutter:
2424
dependencies:
2525
flutter:
2626
sdk: flutter
27-
google_sign_in_android: ^6.2.0
28-
google_sign_in_ios: ^5.8.1
29-
google_sign_in_platform_interface: ^2.5.0
30-
google_sign_in_web: ^0.12.4+4
27+
google_sign_in_android: ^7.0.0
28+
google_sign_in_ios: ^6.0.0
29+
google_sign_in_platform_interface: ^3.0.0
30+
google_sign_in_web: ^1.0.0
3131

3232
dev_dependencies:
3333
build_runner: ^2.1.10
3434
flutter_test:
3535
sdk: flutter
3636
http: ">=0.13.0 <2.0.0"
3737
mockito: ^5.4.4
38+
plugin_platform_interface: ^2.1.8
3839

3940
topics:
4041
- authentication

‎packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart

Lines changed: 539 additions & 378 deletions
Large diffs are not rendered by default.
Lines changed: 54 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Mocks generated by Mockito 5.4.4 from annotations
1+
// Mocks generated by Mockito 5.4.5 from annotations
22
// in google_sign_in/test/google_sign_in_test.dart.
33
// Do not manually edit this file.
44

@@ -18,20 +18,16 @@ import 'package:mockito/mockito.dart' as _i1;
1818
// ignore_for_file: deprecated_member_use_from_same_package
1919
// ignore_for_file: implementation_imports
2020
// ignore_for_file: invalid_use_of_visible_for_testing_member
21+
// ignore_for_file: must_be_immutable
2122
// ignore_for_file: prefer_const_constructors
2223
// ignore_for_file: unnecessary_parenthesis
2324
// ignore_for_file: camel_case_types
2425
// ignore_for_file: subtype_of_sealed_class
2526

26-
class _FakeGoogleSignInTokenData_0 extends _i1.SmartFake
27-
implements _i2.GoogleSignInTokenData {
28-
_FakeGoogleSignInTokenData_0(
29-
Object parent,
30-
Invocation parentInvocation,
31-
) : super(
32-
parent,
33-
parentInvocation,
34-
);
27+
class _FakeAuthenticationResults_0 extends _i1.SmartFake
28+
implements _i2.AuthenticationResults {
29+
_FakeAuthenticationResults_0(Object parent, Invocation parentInvocation)
30+
: super(parent, parentInvocation);
3531
}
3632

3733
/// A class which mocks [GoogleSignInPlatform].
@@ -44,151 +40,78 @@ class MockGoogleSignInPlatform extends _i1.Mock
4440
}
4541

4642
@override
47-
bool get isMock => (super.noSuchMethod(
48-
Invocation.getter(#isMock),
49-
returnValue: false,
50-
) as bool);
51-
52-
@override
53-
_i4.Future<void> init({
54-
List<String>? scopes = const [],
55-
_i2.SignInOption? signInOption = _i2.SignInOption.standard,
56-
String? hostedDomain,
57-
String? clientId,
58-
}) =>
59-
(super.noSuchMethod(
60-
Invocation.method(
61-
#init,
62-
[],
63-
{
64-
#scopes: scopes,
65-
#signInOption: signInOption,
66-
#hostedDomain: hostedDomain,
67-
#clientId: clientId,
68-
},
69-
),
43+
_i4.Future<void> init(_i2.InitParameters? params) => (super.noSuchMethod(
44+
Invocation.method(#init, [params]),
7045
returnValue: _i4.Future<void>.value(),
7146
returnValueForMissingStub: _i4.Future<void>.value(),
7247
) as _i4.Future<void>);
7348

7449
@override
75-
_i4.Future<void> initWithParams(_i2.SignInInitParameters? params) =>
50+
_i4.Future<_i2.AuthenticationResults?>? attemptLightweightAuthentication(
51+
_i2.AttemptLightweightAuthenticationParameters? params,
52+
) =>
7653
(super.noSuchMethod(
77-
Invocation.method(
78-
#initWithParams,
79-
[params],
80-
),
81-
returnValue: _i4.Future<void>.value(),
82-
returnValueForMissingStub: _i4.Future<void>.value(),
83-
) as _i4.Future<void>);
54+
Invocation.method(#attemptLightweightAuthentication, [params]),
55+
) as _i4.Future<_i2.AuthenticationResults?>?);
8456

8557
@override
86-
_i4.Future<_i2.GoogleSignInUserData?> signInSilently() => (super.noSuchMethod(
87-
Invocation.method(
88-
#signInSilently,
89-
[],
58+
_i4.Future<_i2.AuthenticationResults> authenticate(
59+
_i2.AuthenticateParameters? params,
60+
) =>
61+
(super.noSuchMethod(
62+
Invocation.method(#authenticate, [params]),
63+
returnValue: _i4.Future<_i2.AuthenticationResults>.value(
64+
_FakeAuthenticationResults_0(
65+
this,
66+
Invocation.method(#authenticate, [params]),
67+
),
9068
),
91-
returnValue: _i4.Future<_i2.GoogleSignInUserData?>.value(),
92-
) as _i4.Future<_i2.GoogleSignInUserData?>);
69+
) as _i4.Future<_i2.AuthenticationResults>);
9370

9471
@override
95-
_i4.Future<_i2.GoogleSignInUserData?> signIn() => (super.noSuchMethod(
96-
Invocation.method(
97-
#signIn,
98-
[],
99-
),
100-
returnValue: _i4.Future<_i2.GoogleSignInUserData?>.value(),
101-
) as _i4.Future<_i2.GoogleSignInUserData?>);
72+
bool supportsAuthenticate() => (super.noSuchMethod(
73+
Invocation.method(#supportsAuthenticate, []),
74+
returnValue: false,
75+
) as bool);
10276

10377
@override
104-
_i4.Future<_i2.GoogleSignInTokenData> getTokens({
105-
required String? email,
106-
bool? shouldRecoverAuth,
107-
}) =>
108-
(super.noSuchMethod(
109-
Invocation.method(
110-
#getTokens,
111-
[],
112-
{
113-
#email: email,
114-
#shouldRecoverAuth: shouldRecoverAuth,
115-
},
116-
),
117-
returnValue: _i4.Future<_i2.GoogleSignInTokenData>.value(
118-
_FakeGoogleSignInTokenData_0(
119-
this,
120-
Invocation.method(
121-
#getTokens,
122-
[],
123-
{
124-
#email: email,
125-
#shouldRecoverAuth: shouldRecoverAuth,
126-
},
127-
),
128-
)),
129-
) as _i4.Future<_i2.GoogleSignInTokenData>);
78+
bool authorizationRequiresUserInteraction() => (super.noSuchMethod(
79+
Invocation.method(#authorizationRequiresUserInteraction, []),
80+
returnValue: false,
81+
) as bool);
13082

13183
@override
132-
_i4.Future<void> signOut() => (super.noSuchMethod(
133-
Invocation.method(
134-
#signOut,
135-
[],
136-
),
137-
returnValue: _i4.Future<void>.value(),
138-
returnValueForMissingStub: _i4.Future<void>.value(),
139-
) as _i4.Future<void>);
84+
_i4.Future<_i2.ClientAuthorizationTokenData?>
85+
clientAuthorizationTokensForScopes(
86+
_i2.ClientAuthorizationTokensForScopesParameters? params,
87+
) =>
88+
(super.noSuchMethod(
89+
Invocation.method(#clientAuthorizationTokensForScopes, [params]),
90+
returnValue: _i4.Future<_i2.ClientAuthorizationTokenData?>.value(),
91+
) as _i4.Future<_i2.ClientAuthorizationTokenData?>);
14092

14193
@override
142-
_i4.Future<void> disconnect() => (super.noSuchMethod(
143-
Invocation.method(
144-
#disconnect,
145-
[],
146-
),
94+
_i4.Future<_i2.ServerAuthorizationTokenData?>
95+
serverAuthorizationTokensForScopes(
96+
_i2.ServerAuthorizationTokensForScopesParameters? params,
97+
) =>
98+
(super.noSuchMethod(
99+
Invocation.method(#serverAuthorizationTokensForScopes, [params]),
100+
returnValue: _i4.Future<_i2.ServerAuthorizationTokenData?>.value(),
101+
) as _i4.Future<_i2.ServerAuthorizationTokenData?>);
102+
103+
@override
104+
_i4.Future<void> signOut(_i2.SignOutParams? params) => (super.noSuchMethod(
105+
Invocation.method(#signOut, [params]),
147106
returnValue: _i4.Future<void>.value(),
148107
returnValueForMissingStub: _i4.Future<void>.value(),
149108
) as _i4.Future<void>);
150109

151110
@override
152-
_i4.Future<bool> isSignedIn() => (super.noSuchMethod(
153-
Invocation.method(
154-
#isSignedIn,
155-
[],
156-
),
157-
returnValue: _i4.Future<bool>.value(false),
158-
) as _i4.Future<bool>);
159-
160-
@override
161-
_i4.Future<void> clearAuthCache({required String? token}) =>
111+
_i4.Future<void> disconnect(_i2.DisconnectParams? params) =>
162112
(super.noSuchMethod(
163-
Invocation.method(
164-
#clearAuthCache,
165-
[],
166-
{#token: token},
167-
),
113+
Invocation.method(#disconnect, [params]),
168114
returnValue: _i4.Future<void>.value(),
169115
returnValueForMissingStub: _i4.Future<void>.value(),
170116
) as _i4.Future<void>);
171-
172-
@override
173-
_i4.Future<bool> requestScopes(List<String>? scopes) => (super.noSuchMethod(
174-
Invocation.method(
175-
#requestScopes,
176-
[scopes],
177-
),
178-
returnValue: _i4.Future<bool>.value(false),
179-
) as _i4.Future<bool>);
180-
181-
@override
182-
_i4.Future<bool> canAccessScopes(
183-
List<String>? scopes, {
184-
String? accessToken,
185-
}) =>
186-
(super.noSuchMethod(
187-
Invocation.method(
188-
#canAccessScopes,
189-
[scopes],
190-
{#accessToken: accessToken},
191-
),
192-
returnValue: _i4.Future<bool>.value(false),
193-
) as _i4.Future<bool>);
194117
}

‎packages/google_sign_in/google_sign_in/test/widgets_test.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ class _TestGoogleIdentity extends GoogleIdentity {
2828

2929
@override
3030
String? get displayName => null;
31-
32-
@override
33-
String? get serverAuthCode => null;
3431
}
3532

3633
/// A mocked [HttpClient] which always returns a [_MockHttpRequest].

‎script/configs/exclude_all_packages_app.yaml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111

1212
# This is a permanent entry, as it should never be a direct app dependency.
1313
- plugin_platform_interface
14-
# Breaking change in the process of being landed. This will be removed
15-
# once all the layers have landed.
16-
- google_sign_in_platform_interface
17-
- google_sign_in_android
18-
- google_sign_in_ios
19-
- google_sign_in_web
14+
# Temporarily excluded since it hasn't been updated for the major version
15+
# change in google_sign_in. https://github.com/flutter/flutter/issues/171048
16+
- extension_google_sign_in_as_googleapis_auth

0 commit comments

Comments
 (0)
Please sign in to comment.