Flutter - googleapis - How to read email with Gmail Api - flutter

Flutter - How to read email with Gmail Api?
I was looking into googleapis https://pub.dev/packages/googleapis but there is no documentation on how it is actually done.
Can someone point me to a an example or a tutorial?

Here is a complete example:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:zapit/models/appState.dart';
import 'package:googleapis/gmail/v1.dart' as gMail;
class GmailApiScreen extends StatefulWidget {
#override
_GmailApiScreenState createState() => _GmailApiScreenState();
}
class _GmailApiScreenState extends State<GmailApiScreen> {
gMail.GmailApi gmailApi;
List<gMail.Message> messagesList = [];
Future waitForInit;
#override
void initState() {
super.initState();
waitForInit = init();
}
init() async {
final authHeaders = await AppState.state.googleUser.authHeaders;
final authenticateClient = GoogleAuthClient(authHeaders);
gmailApi = gMail.GmailApi(authenticateClient);
gMail.ListMessagesResponse results =
await gmailApi.users.messages.list("me");
for (gMail.Message message in results.messages) {
gMail.Message messageData =
await gmailApi.users.messages.get("me", message.id);
messagesList.add(messageData);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("email")),
body: buildFutureBuilder(),
);
}
FutureBuilder buildFutureBuilder() {
return FutureBuilder(
future: waitForInit,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
List<Widget> messageTxt = [];
for (var m in messagesList) {
messageTxt.add(Text(m.snippet));
}
return Column(
children:messageTxt,
);
} else {
// Otherwise, display a loading indicator.
return Center(child: CircularProgressIndicator());
}
});
}
}
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final http.Client _client = new http.Client();
GoogleAuthClient(this._headers);
Future<http.StreamedResponse> send(http.BaseRequest request) {
return _client.send(request..headers.addAll(_headers));
}
}
the googleUser is created with calling ensureLoggedInOnStartUp in the following code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/gmail/v1.dart' as gMail;
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn.standard(scopes: [gMail.GmailApi.GmailReadonlyScope]);
Future<GoogleSignInAccount> ensureLoggedInOnStartUp() async {
// That class has a currentUser if there's already a user signed in on
// this device.
try {
GoogleSignInAccount googleSignInAccount = googleSignIn.currentUser;
if (googleSignInAccount == null) {
// but if not, Google should try to sign one in whos previously signed in
// on this phone.
googleSignInAccount = await googleSignIn.signInSilently();
if (googleSignInAccount == null) return null;
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential authResult =
await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = await _auth.currentUser;
assert(user.uid == currentUser.uid);
return googleSignInAccount;
}
} catch (e) { //on PlatformException
print(e);
}
return null;
}
Future<GoogleSignInAccount> signInWithGoogle() async {
try {
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
// throws FirebaseException when no internet connection
final UserCredential authResult = await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = await _auth.currentUser;
assert(user.uid == currentUser.uid);
return googleSignInAccount;
} catch (e,s) {
print(e);
print(s);
return null;
}
}
void signOutGoogle() async {
await googleSignIn.signOut();
print("User Sign Out");
}

Related

Flutter - google_sign_in uses allways previously signed in account

I'm trying to sign in and out using firebase google authentication.
When I hit "Sign in with Google", I can choose the account, but the previous user gets loaded.
This is my code of the class that I'm using to log in and log out:
import 'package:flutter/material.dart';
import "package:google_sign_in/google_sign_in.dart";
import "package:firebase_auth/firebase_auth.dart";
import "package:goouser/global.dart" as global;
import 'package:cloud_firestore/cloud_firestore.dart';
class GoogleLog extends ChangeNotifier {
final googleSignIn = GoogleSignIn();
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
Future googleLogin() async {
try {
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_user = googleUser;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
} on Exception catch (e) {
print(e.toString());
}
notifyListeners();
}
Future logOut() async {
await FirebaseAuth.instance.signOut();
await googleSignIn.disconnect();
}
}
I don't know what I am doing wrong!!

Cannot fit requested classes in a single dex file (# methods: 101809 > 65536) com.android.builder.dexing.DexArchiveMergerException:

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:rxdart/rxdart.dart';
import 'homeScreen.dart';
final FirebaseService authService = FirebaseService();
class FirebaseService {
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _db = FirebaseFirestore.instance;
`Observable`<User> user;
`Observable`<Map<String, dynamic>> profile;
PublishSubject loading = PublishSubject();
FirebaseService() {
user = `Observable`(_auth.authStateChanges());
profile = user.switchMap((User u) {
if (u != null) {
return _db
.collection('users')
.doc(u.uid)
.snapshots()
.map((snap) => snap.data());
} else {
return `Observable`.just({});
}
});
}
Future<User> googleSignIn(context) async {
loading.add(true);
GoogleSignInAccount googleUser = `await _googleSignIn.signIn()`;
GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
final authResult = await _auth.signInWithCredential(credential);
if (authResult.user != null) {
Navigator.pushNamed(context, homeScreen.id);
}
updateUserData(`authResult.user`);
print('signed in' + `authResult.user.displayName`);
loading.add(false);
return `authResult.user`;
}
void updateUserData(User user) async {
DocumentReference ref = _db.collection('users').doc(user.uid);
return ref.set(
{
'uid': user.uid,
'email': user.email,
'photoUrl': user.photoURL,
'displayName': user.displayName,
'lastSeen': DateTime.now(),
},
);
}
void signOut() {
_auth.signOut();
}
}
I used this code before 6 months or more and now I face 9 problems inside this code!!
1- Observable not work and I replaced it with Stream and the problem didn't fix!
2- Inside Future<User> googleSignIn(context) the await _googleSignIn.signIn() show a problem!
3- Also inside Future<User> googleSignIn(context) the
updateUserData(authResult.user); print('signed in' + authResult.user.displayName); loading.add(false); return authResult.user; show a problem!
this is the problems showed the studio code
All required libraries added inside pubspec.yeml and I updated them to the newest version.

Flutter Google Sign In error after canceling Choose an account pop-up

After clicking sign in, choose an account pop comes up but if the user pressed back or outside of the pop-up it throws an error.
Error -
Sign in class -
class GoogleSignInProvider extends ChangeNotifier {
final googleSignIn = GoogleSignIn();
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
Future googleLogin() async {
await googleSignIn.signOut();
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_user = googleUser;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
await FirebaseAuth.instance.signInWithCredential(credential);
notifyListeners();
}
}
Sign out button -
TextButton(
onPressed: () async {
final googleCurrentUser = GoogleSignIn().currentUser;
if (googleCurrentUser != null) {
await GoogleSignIn().disconnect();
}
FirebaseAuth.instance.signOut();
Navigator.pop(context);
},
child: const Text(
'Yes',
style: TextStyle(color: primaryColor),
))
Instead of if (googleUser == null) return; try using if (googleUser == null) return null;.
Here is my sign in method;
Future<UserCredential?> signInWithGoogle() async {
final _googleSignIn = GoogleSignIn();
await _googleSignIn.disconnect().catchError((e, stack) {
print(e);
});
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
// handling the exception when cancel sign in
if (googleUser == null) return null;
// Obtain the auth details from the request
final GoogleSignInAuthentication? googleAuth =
await googleUser.authentication;
// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
return await FirebaseAuth.instance.signInWithCredential(credential);
}
The sign out method;
Future signOut() async {
var result = await FirebaseAuth.instance.signOut();
return result;
}
This only happens in debugging, in release this won't be an issue.

Flutter - Google Sign In uses previously signed in account (user) even after signing out and signing in with another account

When I hit "Sign in with Google", it does let me choose the account although somehow, the previous user gets loaded.
class GoogleSignInProvider extends ChangeNotifier {
GoogleSignIn? _googleSignIn;
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
bool _isGoogleLogin = false;
final _auth = FirebaseAuth.instance;
Future signInWithGoogle(context) async {
try {
_googleSignIn = GoogleSignIn();
final googleUser = await _googleSignIn!.signIn();
if (googleUser == null) {
return;
}
_user = googleUser;
final googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
var authCredential = await _auth.signInWithCredential(credential);
_isGoogleLogin = true;
if (authCredential.user != null) {
final snapshot = await FirebaseFirestore.instance
.collection('users')
.doc(authCredential.user!.uid)
.get();
if (!snapshot.exists) {
var userId = authCredential.user!.uid;
FirebaseFirestore.instance.collection('users').doc(userId).set({
"email": googleUser.email,
"workoutsCount": 0,
"lastWorkoutDate": null
});
}
}
notifyListeners();
Navigator.of(context).pushNamed('/dashboard');
} on FirebaseAuthException catch (e) {
showSnackBar(context, e);
} catch (e) {
print('ERROR = ');
print(e);
}
}
Future<void> signOut(context) async {
try {
if (_isGoogleLogin) {
final googleCurrentUser =
GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (googleCurrentUser != null) {
await GoogleSignIn().disconnect().catchError((e, stack) {
FirebaseCrashlytics.instance.recordError(e, stack);
});
}
}
await _auth.signOut();
} catch (e) {
showSnackBar(context, e);
} finally {
_isGoogleLogin = false;
Navigator.of(context).pushNamedAndRemoveUntil(
'/register_login', (Route<dynamic> route) => false);
}
}
Is there something wrong with this code??
Can you try to disconnect the account before signing out:
GoogleSignIn _googleSignIn = GoogleSignIn();
await _googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();
You are using firebase auth then please use thsi for signout user :
How to Signout a user in Flutter with Firebase authentication
Remove if (_isGoogleLogin) from your signOut function. googleCurrentUser will check the consitionn and responses based on the result.
First Create a Global variable
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
GoogleSignIn googleSignIn = GoogleSignIn();
Make sure you are using the above variable for login and logout
final googleCurrentUser = firebaseAuth.currentUser;
if (googleCurrentUser != null) {
googleSignIn.signOut();
await firebaseAuth.signOut();
}
User above code for signout user

Returning Value from Future functions to onPressed method in Flutter

I want to use value returned by Future method and depending on that I want push new routes into the navigator.
I am new with flutter so I don't know how to get values from Future functions. I have tried something like -
final value = await signInWithGoogle();
Future Function Code -
try {
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount
.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final AuthResult result = await _auth.signInWithCredential(credential);
final FirebaseUser user = result.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
if(result.additionalUserInfo.isNewUser){
Navigator.push(context, MaterialPageRoute(builder: (context) => GetInfo()));
}
else {
name = user.displayName;
email = user.email;
imageUrl = user.photoUrl;
return 1;
}
}
catch(e){
print(e.message);
return -1;
}
Try the below code
// 1
// FirebaseAuthUtils
class FirebaseAuthUtils {
final GoogleSignIn _googleSignIn = GoogleSignIn();
Future<User> signInWithGoogle(BuildContext context) async {
User user;
FirebaseUser firebaseuser;
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
firebaseuser = await _auth.signInWithCredential(credential);
assert(!firebaseuser.isAnonymous);
assert(await firebaseuser.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(firebaseuser.uid == currentUser.uid);
} on PlatformException catch (e) {
UtilsImporter().commanUtils.showToast(e.message, context);
}
if (firebaseuser != null) {
user = new User(firebaseuser.displayName, firebaseuser.email, firebaseuser.photoUrl);
}
print('===Google Login: ' + user._fullname);
return user;
}
}
// 2
// User Model
class User {
String _fullname;
String _emailAddress;
String _profilPic;
User(this._fullname, this._emailAddress, this._profilPic);
String get name => _fullname;
set name(String value) {
_fullname = value;
}
String get emailaddress => _emailAddress;
set image(String value) {
_emailAddress = value;
}
String get profilepic => _profilPic;
set profilepic(String value) {
_profilPic = value;
}
}
// 3
// Home Page
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeState();
}
}
class HomeState extends State<Home> {
FirebaseAuthUtils firebaseAuthUtils = new FirebaseAuthUtils();
#override
Widget build(BuildContext context) {
//getting screen size
}
#override
void initState() {
super.initState();
var user = firebaseAuthUtils.signInWithGoogle;
print("User : $user");
}
}
int _value;
#override
void initState() async {
super.initState();
int newValue = await signInWithGoogle();
setState(() {
_value = newValue;
});
}