Flutter Firebase身份验证:启动延迟

时间:2020-03-19 16:00:46

标签: flutter firebase-authentication

我正在使用Provider和应用程序中的流FirebaseAuth.instance.onAuthStateChanged来确定启动时重定向的位置,但是尽管用户已经登录(从以前的启动中),但该应用程序会在登录屏幕上启动,几乎1第二秒后重定向到主页,从第一分钟开始应从该主页开始。即使在飞行模式下也会发生这种情况。

我想知道是否有任何方法可以解决此问题,即使无法一次显示主屏幕,我也不知道如何区分未登录的用户(空->登录屏幕) )并加载用户(null->加载屏幕)。

一些代码:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final DatabaseService db = DatabaseService();
  @override
  Widget build(BuildContext context) {
    return StreamProvider<FirebaseUser>.value(
      value: _auth.onAuthStateChanged,
      child: Consumer<FirebaseUser>(
        builder: (context, firebaseUser, child) {
          return MultiProvider(
            providers: [
              if (firebaseUser != null)
                ChangeNotifierProvider(create: (ctx) => CollectionState(firebaseUser)),
              StreamProvider<List<Collection>>.value(value: db.streamCollections(firebaseUser)),
            ],
            child: MaterialApp(
              title: 'My App',
              routes: {
                '/': (ctx) => LandingPage(),
                '/login': (ctx) => LoginPage(),
                '/emailSignIn': (ctx) => EmailSignInPage(),
                '/emailSignUp': (ctx) => EmailSignUpPage(),
                '/emailUnverified': (ctx) => EmailUnverifiedPage(),
                '/home': (ctx) => HomePage(),
                '/settings': (ctx) => Settings(),
              },
            ),
          );
        },
      ),
    );
  }
}

class LandingPage extends StatelessWidget {
  final DatabaseService _db = DatabaseService();
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<FirebaseUser>(context);
    final userCondition =
        user == null ? 'null' : user.isEmailVerified ? 'verifiedUser' : 'unverifiedUser';

    switch (userCondition) {
      case 'null':
        return LoginPage();
        break;
      case 'unverifiedUser':
        return EmailUnverifiedPage();
        break;
      case 'verifiedUser':
        return HomePage();
        break;
    }
  }
}

代码略有简化,我只是将服务用于身份验证实例。

3 个答案:

答案 0 :(得分:1)

我知道我已经很晚了,但是我遇到了同样的问题几周了,终于找到答案了。

@ChinkySight是正确的,他说最好使用StreamBuilder,主要是因为您可以访问connectionState属性。

之所以存在延迟,是因为与流的连接未完全建立。因此,在ConnectionState.waiting期间,返回一个小部件,例如启动屏幕或只是一个容器。

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: FirebaseAuth.instance.onAuthStateChanged,
        builder: (_, snapshot) {
          // Added this line
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Container();
          }
          if (snapshot.data is FirebaseUser && snapshot.data != null) {
            return HomePage();
          }
          return LoginPage();
        });
  }
}

您甚至可以使用Animated Switcher给返回语句添加精美的动画

return StreamBuilder(
      stream: FirebaseAuth.instance.onAuthStateChanged,
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        Widget widget;

        if (snapshot.connectionState == ConnectionState.waiting) {
          return Container();
        }

        switch (snapshot.hasData) {
          case (true):
            widget = HomePage();
            break;
          case (false):
            widget = LoginPage();
        }
        return Stack(
          children: <Widget>[
            Scaffold(
              backgroundColor: Colors.grey.shade200,
            ),
            AnimatedSwitcher(
              duration: Duration(milliseconds: 700),
              child: FadeTransition(
                  opacity: animation,
                  child: widget,
                ),
               );
              },
            )
          ],
        );
      },
    );

答案 1 :(得分:1)

这适用于FlutterFire

Firebase Auth使您可以通过以下方式实时订阅此状态 流。调用后,该流将立即提供 用户的当前身份验证状态,然后提供后续 身份验证状态更改时发生的事件。订阅 这些更改后,请在FirebaseAuth上调用authStateChanges()方法 实例:

import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:flutter/material.dart';
import 'menu.dart';
import 'login.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';

Future main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      runApp(
          MyApp()
        );
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitUp]);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'TestApp',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: 
        StreamBuilder<auth.User>(
          stream: auth.FirebaseAuth.instance.authStateChanges(),
          builder: (BuildContext context, AsyncSnapshot<auth.User> snapshot) { 
            if(snapshot.hasData) {
              print("data exists");
              return HomePage();
            }
            else {
              return LoginPage();
            }
          },
        )
    );
  }
}

答案 2 :(得分:-1)

但是,尽管用户已经登录(以前的启动) 该应用程序在登录屏幕上启动,并在大约1秒后重定向 到主页,应该从第一个开始 片刻。

在这种情况下,最佳实践是使用包装器,该包装器将根据流FirebaseAuth.instance.onAuthStateChanged

决定导航

说明:

您可能熟悉FirebaseAuth.instance.onAuthStateChanged,当我们登录时会给出FirebaseUser,而在没有登录时会给出null。因此,基于此流,我将返回小部件。如果流提供的是FirebaseUser而不是null,这显然意味着用户已登录,则返回HomePage();否则,如果用户未登录,则只需返回{{1} }

因此,您不必担心已登录的用户,导航到LoginPage(),然后在第二次重定向到LoginPage之后。每当流中发生更改时,HomePage都会重建(StreamBuilder仅在执行登录或注销时更改)。如果用户退出 FirebaseAuth.instance.onAuthStateChanged将自行重建并返回StreamBuilder,因此您无需手动导航至LoginPage

LoginPage