Gilberg
Gilberg

Reputation: 2564

How do I use onAuthStateChanged for Firebase Auth in Flutter?

  1. I am using firebase auth and google sign in to handle authentication.
  2. As of now I am able to sign into my flutter app using firebase_auth/google_sign_in.
  3. I am using the firebase_auth.dart plugin from: https://pub.dartlang.org/packages/firebase_auth
  4. I am using onAuthStateChanged to detect when a user has signed in and it all works fine.
  5. My problem is: When I sign out, onAuthStateChanged doesn't seem to notice

Here is my code (right now the "app" is just some dummy pages)

import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:flutter/foundation.dart';

// ************** Begin Auth

final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = new GoogleSignIn();

Future<FirebaseUser> signInWithGoogle() async {
  // Attempt to get the currently authenticated user
  GoogleSignInAccount currentUser = _googleSignIn.currentUser;
  if (currentUser == null) {
    // Attempt to sign in without user interaction
    currentUser = await _googleSignIn.signInSilently();
  }
  if (currentUser == null) {
    // Force the user to interactively sign in
    currentUser = await _googleSignIn.signIn();
  }

  final GoogleSignInAuthentication auth = await currentUser.authentication;

  // Authenticate with firebase
  final FirebaseUser user = await _auth.signInWithGoogle(
    idToken: auth.idToken,
    accessToken: auth.accessToken,
  );

  assert(user != null);
  assert(!user.isAnonymous);

  return user;
}


Future<Null> signOutWithGoogle() async {
  debugPrint('in the SIGN OUT FUNCTION');
  await _auth.signOut();
  await _googleSignIn.signOut();

}

// ************** ENd Auth

void main() => runApp(new MyApp());


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.yellow,
      ),
      home: new SplashPage(),
      routes: <String, WidgetBuilder>{
        '/login': (BuildContext context) => new LoginPage(),
        '/app': (BuildContext context) => new AppPage(),
      },
    );
  }
}

class SplashPage extends StatefulWidget {
  @override
  State createState() => new _SplashPageState();
}

class _SplashPageState extends State<SplashPage> {
  final FirebaseAuth _auth = FirebaseAuth.instance;



  @override
  void initState() {
    super.initState();

    _auth.onAuthStateChanged.firstWhere((user) => user != null).then((user) {
      debugPrint('AUTH STATE HAS CHANGED');
      debugPrint('user id: '+user.uid);
      Navigator.of(context).pushReplacementNamed('/app');
    });

    new Future.delayed(new Duration(seconds: 1)).then((_) => signInWithGoogle());
  }

  @override
  Widget build(BuildContext context) {
    return new Text('splash 123');
  }
}


class AppPage extends StatelessWidget {

  void _logout(){
    debugPrint('pressed logout button');
    signOutWithGoogle();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('In Da App'),
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list), onPressed: _logout),
        ],
      ),
      body: new Text('Welcome'),
    );
  }
}

class LoginPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Text('You gotta login'),
    );
  }
}

Why isn't onAuthStateChanged detecting when a user has logged out. Also, here is a screenshot of my console when I click the logout button.

enter image description here

based on the console output I can confirm that the code is in fact reaching the sign out function based on my debugPrint() that I have in there. I find it curious that the console is logging:

"Notifying auth state listeners." 

and then logging right after that:

"Notified 0 auth state listeners."

Upvotes: 3

Views: 5212

Answers (1)

westoque
westoque

Reputation: 417

You should use a StreamBuilder to make sure your widget gets notified. If you look at onAuthStateChanged it actually returns a Stream<FirebaseUser>

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new StreamBuilder(
        stream: _auth.onAuthStateChanged,
        builder: (context, snapshot) {
          // Simple case
          if (snapshot.hasData) {
            return AppPage();
          }

          return SplashPage();
        },
      ),
    );
  }
}

Upvotes: 8

Related Questions