@@ -10,13 +10,12 @@ import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sig
1010import 'package:flutter/material.dart' ;
1111import 'package:google_sign_in/google_sign_in.dart' ;
1212import 'package:googleapis/people/v1.dart' ;
13+ // #docregion CreateAPIClient
1314import 'package:googleapis_auth/googleapis_auth.dart' as auth show AuthClient;
15+ // #enddocregion CreateAPIClient
1416
15- final GoogleSignIn _googleSignIn = GoogleSignIn (
16- // Optional clientId
17- // clientId: '[YOUR_OAUTH_2_CLIENT_ID]',
18- scopes: < String > [PeopleServiceApi .contactsReadonlyScope],
19- );
17+ /// The scopes used by this example.
18+ const List <String > scopes = < String > [PeopleServiceApi .contactsReadonlyScope];
2019
2120void main () {
2221 runApp (
@@ -38,37 +37,84 @@ class SignInDemo extends StatefulWidget {
3837
3938/// The state of the main widget.
4039class SignInDemoState extends State <SignInDemo > {
40+ late Future <void > _signInInitialized;
4141 GoogleSignInAccount ? _currentUser;
42+ GoogleSignInClientAuthorization ? _authorization;
4243 String _contactText = '' ;
4344
4445 @override
4546 void initState () {
4647 super .initState ();
47- _googleSignIn.onCurrentUserChanged.listen ((GoogleSignInAccount ? account) {
48+
49+ final GoogleSignIn signIn = GoogleSignIn .instance;
50+ _signInInitialized = signIn.initialize (
51+ // Add your client IDs here as necessary for your supported platforms.
52+ );
53+ signIn.authenticationEvents.listen ((GoogleSignInAuthenticationEvent event) {
54+ if (! mounted) {
55+ return ;
56+ }
4857 setState (() {
49- _currentUser = account;
58+ switch (event) {
59+ case GoogleSignInAuthenticationEventSignIn ():
60+ _currentUser = event.user;
61+ case GoogleSignInAuthenticationEventSignOut ():
62+ _currentUser = null ;
63+ _authorization = null ;
64+ }
5065 });
66+
5167 if (_currentUser != null ) {
52- _handleGetContact ();
68+ _checkAuthorization ();
5369 }
70+ }).onError ((Object error) {
71+ debugPrint (error.toString ());
72+ });
73+
74+ _signInInitialized.then ((void value) {
75+ signIn.attemptLightweightAuthentication ();
5476 });
55- _googleSignIn.signInSilently ();
5677 }
5778
58- Future <void > _handleGetContact () async {
79+ void _updateAuthorization (GoogleSignInClientAuthorization ? authorization) {
80+ if (! mounted) {
81+ return ;
82+ }
5983 setState (() {
60- _contactText = 'Loading contact info...' ;
84+ _authorization = authorization ;
6185 });
6286
63- // #docregion CreateAPIClient
64- // Retrieve an [auth.AuthClient] from the current [GoogleSignIn] instance.
65- final auth.AuthClient ? client = await _googleSignIn.authenticatedClient ();
87+ if (authorization != null ) {
88+ unawaited (_handleGetContact (authorization));
89+ }
90+ }
6691
67- assert (client != null , 'Authenticated client missing!' );
92+ Future <void > _checkAuthorization () async {
93+ _updateAuthorization (
94+ await _currentUser? .authorizationClient.authorizationForScopes (scopes));
95+ }
96+
97+ Future <void > _requestAuthorization () async {
98+ _updateAuthorization (await _currentUser? .authorizationClient
99+ .authorizeScopes (< String > [PeopleServiceApi .contactsReadonlyScope]));
100+ }
101+
102+ Future <void > _handleGetContact (
103+ GoogleSignInClientAuthorization authorization) async {
104+ if (! mounted) {
105+ return ;
106+ }
107+ setState (() {
108+ _contactText = 'Loading contact info...' ;
109+ });
110+
111+ // #docregion CreateAPIClient
112+ // Retrieve an [auth.AuthClient] from a GoogleSignInClientAuthorization.
113+ final auth.AuthClient client = authorization.authClient (scopes: scopes);
68114
69115 // Prepare a People Service authenticated client.
70- final PeopleServiceApi peopleApi = PeopleServiceApi (client! );
71- // Retrieve a list of the `names` of my `connections`
116+ final PeopleServiceApi peopleApi = PeopleServiceApi (client);
117+ // Retrieve a list of connected contacts' names.
72118 final ListConnectionsResponse response =
73119 await peopleApi.people.connections.list (
74120 'people/me' ,
@@ -79,13 +125,15 @@ class SignInDemoState extends State<SignInDemo> {
79125 final String ? firstNamedContactName =
80126 _pickFirstNamedContact (response.connections);
81127
82- setState (() {
83- if (firstNamedContactName != null ) {
84- _contactText = 'I see you know $firstNamedContactName !' ;
85- } else {
86- _contactText = 'No contacts to display.' ;
87- }
88- });
128+ if (mounted) {
129+ setState (() {
130+ if (firstNamedContactName != null ) {
131+ _contactText = 'I see you know $firstNamedContactName !' ;
132+ } else {
133+ _contactText = 'No contacts to display.' ;
134+ }
135+ });
136+ }
89137 }
90138
91139 String ? _pickFirstNamedContact (List <Person >? connections) {
@@ -102,51 +150,72 @@ class SignInDemoState extends State<SignInDemo> {
102150
103151 Future <void > _handleSignIn () async {
104152 try {
105- await _googleSignIn. signIn ();
153+ await GoogleSignIn .instance. authenticate ();
106154 } catch (error) {
107- print (error); // ignore: avoid_print
155+ debugPrint (error. toString ());
108156 }
109157 }
110158
111- Future <void > _handleSignOut () => _googleSignIn.disconnect ();
159+ // Call disconnect rather than signOut to more fully reset the example app.
160+ Future <void > _handleSignOut () => GoogleSignIn .instance.disconnect ();
112161
113162 Widget _buildBody () {
114- final GoogleSignInAccount ? user = _currentUser;
115- if (user != null ) {
116- return Column (
117- mainAxisAlignment: MainAxisAlignment .spaceAround,
118- children: < Widget > [
119- ListTile (
120- leading: GoogleUserCircleAvatar (
121- identity: user,
122- ),
123- title: Text (user.displayName ?? '' ),
124- subtitle: Text (user.email),
125- ),
126- const Text ('Signed in successfully.' ),
127- Text (_contactText),
128- ElevatedButton (
129- onPressed: _handleSignOut,
130- child: const Text ('SIGN OUT' ),
131- ),
132- ElevatedButton (
133- onPressed: _handleGetContact,
134- child: const Text ('REFRESH' ),
135- ),
136- ],
137- );
138- } else {
139- return Column (
140- mainAxisAlignment: MainAxisAlignment .spaceAround,
141- children: < Widget > [
142- const Text ('You are not currently signed in.' ),
143- ElevatedButton (
144- onPressed: _handleSignIn,
145- child: const Text ('SIGN IN' ),
146- ),
147- ],
148- );
149- }
163+ return FutureBuilder <void >(
164+ future: _signInInitialized,
165+ builder: (BuildContext context, AsyncSnapshot <void > snapshot) {
166+ final GoogleSignInAccount ? user = _currentUser;
167+ final GoogleSignInClientAuthorization ? authorization = _authorization;
168+ final List <Widget > children;
169+ if (snapshot.hasError) {
170+ children = < Widget > [
171+ const Text ('Error initializing sign in.' ),
172+ ];
173+ } else if (snapshot.connectionState == ConnectionState .done) {
174+ children = < Widget > [
175+ if (user != null ) ...< Widget > [
176+ ListTile (
177+ leading: GoogleUserCircleAvatar (
178+ identity: user,
179+ ),
180+ title: Text (user.displayName ?? '' ),
181+ subtitle: Text (user.email),
182+ ),
183+ const Text ('Signed in successfully.' ),
184+ if (authorization != null ) ...< Widget > [
185+ Text (_contactText),
186+ ElevatedButton (
187+ onPressed: () => _handleGetContact (authorization),
188+ child: const Text ('REFRESH' ),
189+ ),
190+ ] else ...< Widget > [
191+ ElevatedButton (
192+ onPressed: _requestAuthorization,
193+ child: const Text ('LOAD CONTACTS' ),
194+ ),
195+ ],
196+ ElevatedButton (
197+ onPressed: _handleSignOut,
198+ child: const Text ('SIGN OUT' ),
199+ ),
200+ ] else ...< Widget > [
201+ const Text ('You are not currently signed in.' ),
202+ ElevatedButton (
203+ onPressed: _handleSignIn,
204+ child: const Text ('SIGN IN' ),
205+ ),
206+ ],
207+ ];
208+ } else {
209+ children = < Widget > [
210+ const CircularProgressIndicator (),
211+ ];
212+ }
213+
214+ return Column (
215+ mainAxisAlignment: MainAxisAlignment .spaceAround,
216+ children: children,
217+ );
218+ });
150219 }
151220
152221 @override
0 commit comments