Skip to content

Commit a5188a4

Browse files
[google_sign_in] Redesign API for current identity SDKs - Platform Interface (#9454)
This is the platform interface portion of #9267 It intentional makes breaking changes to the platform interface package, for the reasons described in the main PR. Part of flutter/flutter#119300 ## 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 02770da commit a5188a4

File tree

9 files changed

+541
-550
lines changed

9 files changed

+541
-550
lines changed

packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
## NEXT
1+
## 3.0.0
22

3+
* **BREAKING CHANGE**: Overhauls the entire API surface to better abstract the
4+
current set of underlying platform SDKs, and to use structured errors. See
5+
API doc comments for details on the behaviors that platform implementations
6+
must implement.
37
* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6.
48

59
## 2.5.0

packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart

Lines changed: 110 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@
44

55
import 'dart:async';
66

7-
import 'package:flutter/foundation.dart' show visibleForTesting;
87
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
98

10-
import 'src/method_channel_google_sign_in.dart';
119
import 'src/types.dart';
1210

13-
export 'src/method_channel_google_sign_in.dart';
1411
export 'src/types.dart';
1512

1613
/// The interface that implementations of google_sign_in must implement.
@@ -27,134 +24,151 @@ abstract class GoogleSignInPlatform extends PlatformInterface {
2724

2825
static final Object _token = Object();
2926

30-
/// Only mock implementations should set this to `true`.
27+
/// The instance of [GoogleSignInPlatform] to use.
3128
///
32-
/// Mockito mocks implement this class with `implements` which is forbidden
33-
/// (see class docs). This property provides a backdoor for mocks to skip the
34-
/// verification that the class isn't implemented with `implements`.
35-
@visibleForTesting
36-
@Deprecated('Use MockPlatformInterfaceMixin instead')
37-
bool get isMock => false;
38-
39-
/// The default instance of [GoogleSignInPlatform] to use.
40-
///
41-
/// Platform-specific plugins should override this with their own
29+
/// Platform-implementations should override this with their own
4230
/// platform-specific class that extends [GoogleSignInPlatform] when they
4331
/// register themselves.
4432
///
4533
/// Defaults to [MethodChannelGoogleSignIn].
4634
static GoogleSignInPlatform get instance => _instance;
4735

48-
static GoogleSignInPlatform _instance = MethodChannelGoogleSignIn();
36+
static GoogleSignInPlatform _instance = _PlaceholderImplementation();
4937

50-
// TODO(amirh): Extract common platform interface logic.
51-
// https://github.com/flutter/flutter/issues/43368
5238
static set instance(GoogleSignInPlatform instance) {
53-
if (!instance.isMock) {
54-
PlatformInterface.verify(instance, _token);
55-
}
39+
PlatformInterface.verify(instance, _token);
5640
_instance = instance;
5741
}
5842

59-
/// Initializes the plugin. Deprecated: call [initWithParams] instead.
43+
/// Initializes the plugin with specified [params]. You must call this method
44+
/// before calling other methods.
6045
///
61-
/// The [hostedDomain] argument specifies a hosted domain restriction. By
62-
/// setting this, sign in will be restricted to accounts of the user in the
63-
/// specified domain. By default, the list of accounts will not be restricted.
46+
/// See:
6447
///
65-
/// The list of [scopes] are OAuth scope codes to request when signing in.
66-
/// These scope codes will determine the level of data access that is granted
67-
/// to your application by the user. The full list of available scopes can be
68-
/// found here: <https://developers.google.com/identity/protocols/googlescopes>
48+
/// * [InitParameters]
49+
Future<void> init(InitParameters params);
50+
51+
/// Attempts to sign in without an explicit user intent.
6952
///
70-
/// The [signInOption] determines the user experience. [SigninOption.games] is
71-
/// only supported on Android.
53+
/// This is intended to support the use case where the user might be expected
54+
/// to be signed in, but hasn't explicitly requested sign in, such as when
55+
/// launching an application that is intended to be used while signed in.
7256
///
73-
/// See:
74-
/// https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams
75-
Future<void> init({
76-
List<String> scopes = const <String>[],
77-
SignInOption signInOption = SignInOption.standard,
78-
String? hostedDomain,
79-
String? clientId,
80-
}) async {
81-
throw UnimplementedError('init() has not been implemented.');
82-
}
57+
/// This may be silent, or may show minimal UI, depending on the platform and
58+
/// the context.
59+
Future<AuthenticationResults?>? attemptLightweightAuthentication(
60+
AttemptLightweightAuthenticationParameters params);
8361

84-
/// Initializes the plugin with specified [params]. You must call this method
85-
/// before calling other methods.
62+
/// Returns true if the platform implementation supports the [authenticate]
63+
/// method.
8664
///
87-
/// See:
65+
/// The default is true, but platforms that cannot support [authenticate] can
66+
/// override this to return false, throw [UnsupportedError] from
67+
/// [authenticate], and provide a different, platform-specific authentication
68+
/// flow.
69+
bool supportsAuthenticate();
70+
71+
/// Signs in with explicit user intent.
8872
///
89-
/// * [SignInInitParameters]
90-
Future<void> initWithParams(SignInInitParameters params) async {
91-
await init(
92-
scopes: params.scopes,
93-
signInOption: params.signInOption,
94-
hostedDomain: params.hostedDomain,
95-
clientId: params.clientId,
96-
);
97-
}
73+
/// This is intended to support the use case where the user has expressed
74+
/// an explicit intent to sign in.
75+
Future<AuthenticationResults> authenticate(AuthenticateParameters params);
9876

99-
/// Attempts to reuse pre-existing credentials to sign in again, without user interaction.
100-
Future<GoogleSignInUserData?> signInSilently() async {
101-
throw UnimplementedError('signInSilently() has not been implemented.');
102-
}
77+
/// Whether or not authorization calls that could show UI must be called from
78+
/// a user interaction, such as a button press, on the current platform.
79+
///
80+
/// Platforms that can fail to show UI without an active user interaction,
81+
/// such as a web implementations that uses popups, should return false.
82+
bool authorizationRequiresUserInteraction();
10383

104-
/// Signs in the user with the options specified to [init].
105-
Future<GoogleSignInUserData?> signIn() async {
106-
throw UnimplementedError('signIn() has not been implemented.');
84+
/// Returns the tokens used to authenticate other API calls from a client.
85+
///
86+
/// This should only return null if prompting would be necessary but [params]
87+
/// do not allow it, otherwise any failure should return an error.
88+
Future<ClientAuthorizationTokenData?> clientAuthorizationTokensForScopes(
89+
ClientAuthorizationTokensForScopesParameters params);
90+
91+
/// Returns the tokens used to authenticate other API calls from a server.
92+
///
93+
/// This should only return null if prompting would be necessary but [params]
94+
/// do not allow it, otherwise any failure should return an error.
95+
Future<ServerAuthorizationTokenData?> serverAuthorizationTokensForScopes(
96+
ServerAuthorizationTokensForScopesParameters params);
97+
98+
/// Signs out previously signed in accounts.
99+
Future<void> signOut(SignOutParams params);
100+
101+
/// Revokes all of the scopes that all signed in users granted, and then signs
102+
/// them out.
103+
Future<void> disconnect(DisconnectParams params);
104+
105+
/// Returns a stream of authentication events.
106+
///
107+
/// If this is not overridden, the app-facing package will assume that the
108+
/// futures returned by [attemptLightweightAuthentication], [authenticate],
109+
/// and [signOut] are the only sources of authentication-related events.
110+
/// Implementations that have other sources should override this and provide
111+
/// a stream with all authentication and sign-out events.
112+
/// These will normally come from asynchronous flows, like the authenticate
113+
/// and signOut methods, as well as potentially from platform-specific methods
114+
/// (such as the Google Sign-In Button Widget from the Web implementation).
115+
///
116+
/// Implementations should never intentionally call `addError` for this
117+
/// stream, and should instead use AuthenticationEventException. This is to
118+
/// ensure via the type system that implementations are always sending
119+
/// [GoogleSignInException] for know failure cases.
120+
Stream<AuthenticationEvent>? get authenticationEvents => null;
121+
}
122+
123+
/// An implementation of GoogleSignInPlatform that throws unimplemented errors,
124+
/// to use as a default instance if no platform implementation has been
125+
/// registered.
126+
class _PlaceholderImplementation extends GoogleSignInPlatform {
127+
@override
128+
Future<void> init(InitParameters params) {
129+
throw UnimplementedError();
107130
}
108131

109-
/// Returns the Tokens used to authenticate other API calls.
110-
Future<GoogleSignInTokenData> getTokens(
111-
{required String email, bool? shouldRecoverAuth}) async {
112-
throw UnimplementedError('getTokens() has not been implemented.');
132+
@override
133+
Future<AuthenticationResults?> attemptLightweightAuthentication(
134+
AttemptLightweightAuthenticationParameters params) {
135+
throw UnimplementedError();
113136
}
114137

115-
/// Signs out the current account from the application.
116-
Future<void> signOut() async {
117-
throw UnimplementedError('signOut() has not been implemented.');
138+
@override
139+
bool supportsAuthenticate() {
140+
throw UnimplementedError();
118141
}
119142

120-
/// Revokes all of the scopes that the user granted.
121-
Future<void> disconnect() async {
122-
throw UnimplementedError('disconnect() has not been implemented.');
143+
@override
144+
Future<AuthenticationResults> authenticate(AuthenticateParameters params) {
145+
throw UnimplementedError();
123146
}
124147

125-
/// Returns whether the current user is currently signed in.
126-
Future<bool> isSignedIn() async {
127-
throw UnimplementedError('isSignedIn() has not been implemented.');
148+
@override
149+
bool authorizationRequiresUserInteraction() {
150+
throw UnimplementedError();
128151
}
129152

130-
/// Clears any cached information that the plugin may be holding on to.
131-
Future<void> clearAuthCache({required String token}) async {
132-
throw UnimplementedError('clearAuthCache() has not been implemented.');
153+
@override
154+
Future<ClientAuthorizationTokenData?> clientAuthorizationTokensForScopes(
155+
ClientAuthorizationTokensForScopesParameters params) {
156+
throw UnimplementedError();
133157
}
134158

135-
/// Requests the user grants additional Oauth [scopes].
136-
///
137-
/// Scopes should come from the full list
138-
/// [here](https://developers.google.com/identity/protocols/googlescopes).
139-
Future<bool> requestScopes(List<String> scopes) async {
140-
throw UnimplementedError('requestScopes() has not been implemented.');
159+
@override
160+
Future<ServerAuthorizationTokenData?> serverAuthorizationTokensForScopes(
161+
ServerAuthorizationTokensForScopesParameters params) {
162+
throw UnimplementedError();
141163
}
142164

143-
/// Checks if the current user has granted access to all the specified [scopes].
144-
///
145-
/// Optionally, an [accessToken] can be passed for applications where a
146-
/// long-lived token may be cached (like the web).
147-
Future<bool> canAccessScopes(
148-
List<String> scopes, {
149-
String? accessToken,
150-
}) async {
151-
throw UnimplementedError('canAccessScopes() has not been implemented.');
165+
@override
166+
Future<void> signOut(SignOutParams params) {
167+
throw UnimplementedError();
152168
}
153169

154-
/// Returns a stream of [GoogleSignInUserData] authentication events.
155-
///
156-
/// These will normally come from asynchronous flows, like the Google Sign-In
157-
/// Button Widget from the Web implementation, and will be funneled directly
158-
/// to the `onCurrentUserChanged` Stream of the plugin.
159-
Stream<GoogleSignInUserData?>? get userDataEvents => null;
170+
@override
171+
Future<void> disconnect(DisconnectParams params) {
172+
throw UnimplementedError();
173+
}
160174
}

packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart

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

0 commit comments

Comments
 (0)