Flutter 中的 authStateChanges 问题

Jaz*_*aim 10 dart firebase firebase-authentication flutter

每当用户关闭应用程序时,他们都必须重新登录。我查看并尝试实现 authStateChanges。但是我的应用程序仍然强迫用户在关闭应用程序后重新登录。在 App 类中,您可以看到我试图完全执行 authStateChange,但不幸的是,似乎什么也没发生。

Future<void> main() async {


WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(App());
}

// Firebase Auth Instance
FirebaseAuth auth = FirebaseAuth.instance;

class MyApp extends StatelessWidget {
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();



// This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
  title: 'Tanbo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  home: LoginPage(),
);


}
}

// This is the main root screen of the Tanbo app
class App extends StatelessWidget {
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();



@override
  Widget build(BuildContext context) {
    return FutureBuilder(
      // Initialize FlutterFire
      future: _initialization,
  

builder: (context, snapshot) {
    final user = FirebaseAuth.instance.authStateChanges().listen((User user) {
      if (user == null) {
        print('User signed out');
      } else {
        print('User signed in');
      }
    });

    // Check for errors
    if (snapshot.hasError) {
      return ErrorHandler();
    }

    // Once complete, show your application
    if (snapshot.connectionState == ConnectionState.done) {
      // If the user isn't logged in, we will be sent to sign up page.
      if (user != null) {
        return MyApp();
      } else {
        // If the user is logged in, TabHandler will be shown.
        return TabHandler();
      }
    }

    // Otherwise, show something whilst waiting for initialization to complete
    return LoadingHandler();
  },
);


 }
}
Run Code Online (Sandbox Code Playgroud)

Sim*_*eon 21

问题是您已明确将登录页面设为主页。当应用程序打开时,它会自动读取main.dart文件并将登录页面视为指定的主页。

这就是你修复它的方法。并制作一个身份验证系统,您可以在应用程序中的任何位置获取登录用户的 ID。

你需要什么:

  1. 任何版本的提供程序依赖项。最好是最新的
  2. 微笑——别皱眉了。你即将解决你的问题
  3. Firebase 身份验证依赖项。无论在哪个版本。我将为您提供最新版本和明显旧版本的修复程序。

步骤 0:添加所需的依赖项并运行 flutter pub get。这是一个没有脑子的。

第1步:创建一个auth_services类:代码如下

对于旧版本firebase auth

import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

class AuthService {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  Stream<String> get onAuthStateChanged =>
      _firebaseAuth.onAuthStateChanged.map(
            (FirebaseUser user) => user?.uid,
      );

  // GET UID
  Future<String> getCurrentUID() async {
    return (await _firebaseAuth.currentUser()).uid;
  }
}
Run Code Online (Sandbox Code Playgroud)

对于较新版本的 firebase auth 依赖项:

class AuthService {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  Stream<User> get onAuthStateChanged => _firebaseAuth.authStateChanges();

  // GET UID
  Future<String> getCurrentUID() async {
    return _firebaseAuth.currentUser.uid;
  }
}
Run Code Online (Sandbox Code Playgroud)

说明:我已经让这个类来处理所有的身份验证功能。我正在制作一个名为 onAuthStateChanged 的​​函数,它返回一个 User 类型的流(旧版 firebase auth 的 ID),我将监听这个流以确定是否有用户登录。

第 2 步:创建将包装整个应用程序的身份验证提供程序,并使我们可以在应用程序的任何位置获取我们的用户 ID。

创建一个名为 auth_provider.dart 的文件。代码如下。

import 'package:flutter/material.dart';
import 'auth_service.dart';

class Provider extends InheritedWidget {
  final AuthService auth;
  Provider({
    Key key,
    Widget child,
    this.auth,
  }) : super(key: key, child: child);

  @override
  bool updateShouldNotify(InheritedWidget oldWiddget) {
    return true;
  }

  static Provider of(BuildContext context) =>
      (context.dependOnInheritedWidgetOfExactType<Provider>());
}
Run Code Online (Sandbox Code Playgroud)

下一步是将整个应用程序包装在此提供程序小部件中,并将家庭控制器设置为主页。

第 3 步:在 main.dart 文件或任何地方,创建一个名为 HomeController 的类来处理登录状态,并将 home Controller 设置为指定的主页。

注意:我设置了一个黑色容器,在应用加载时显示,以确定用户是否登录。这是一个相当快的过程,但如果您愿意,可以将其设置为应用程序主题颜色的容器。您甚至可以将其设置为启动画面。(请注意。此容器最多显示约 1 秒。根据我的经验)

代码如下:导入所有必要的东西

void main() {
 //WidgetsFlutterBinding.ensureInitialized();
 // await Firebase.initializeApp();
//only add these if you're on the latest firebase
  runApp(MyApp());
}

 class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Provider(
      auth: AuthService(),
      child: MaterialApp(
            title: 'Dreamora',
            theme: ThemeData(
              // fontFamily: "Montserrat",
              brightness: Brightness.light,
              inputDecorationTheme: InputDecorationTheme(
                contentPadding:
                    EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(5.0),
                ),
              ),
              primarySwatch: Colors.purple,
              visualDensity: VisualDensity.adaptivePlatformDensity,
            ),
            home: HomeController(),
          );
        },
      ),
    ),}
//(I think i have messed up the brackets here, but, you get the 
//gist)

class HomeController extends StatelessWidget {
  const HomeController({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final AuthService auth = Provider.of(context).auth;

    return StreamBuilder(
      stream: auth.onAuthStateChanged,
      builder: (context, AsyncSnapshot<String> snapshot) {
        if (snapshot.connectionState == ConnectionState.active) {
          final bool signedIn = snapshot.hasData;
          return signedIn ? DashBoard() : FirstView();
        }
        return Container(
          color: Colors.black,
        );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

说明:家庭控制器只是一个 Steam 生成器,它监听我们所做的 steam auth 更改。如果有任何东西,则用户已登录。如果没有,则他已注销。相当简单。虽然在确定用户的登录状态之间有 1 秒的延迟。Soo,我当时要退回一个黑色的容器。打开应用程序后,用户将看到屏幕变黑约一秒钟,然后轰隆隆。主页

重要提示:您应该使用提供程序包装您的整个应用程序。这个很重要。请不要忘了。

如何在应用程序中的任何点获取用户 ID

Provider.of(context).auth.getCurrentUID()
Run Code Online (Sandbox Code Playgroud)

你去吧。享受

[编辑]正如 L. Gangemi 所说,新版本的 Firebase Auth 返回用户流。所以将家庭控制器代码编辑为

builder: (context, AsyncSnapshot<User> snapshot) {
Run Code Online (Sandbox Code Playgroud)

  • 你的回答非常有用。我只是想说,在最新版本中,您的代码返回带有流的 User,因此 StreamBuilder 中的 AsyncSnaphot 应该类似于: AsyncSnapshot&lt;User&gt; (2认同)