You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter+Firebase电话认证:退出登录后重新登录异常问题求助

问题解决:Firebase电话认证Flutter应用退出登录后无需重启即可重新登录

问题描述

我在基于Firebase电话认证的Flutter应用中实现退出登录功能时遇到问题:点击退出按钮后应用跳转至首页,但再次进行电话认证时无法正常进入主页,因为用户数据仍被保存。若删除退出方法中的runApp(ProviderScope(...))代码,仅在重启应用后退出登录才会生效,需要解决无需重启应用即可正常完成重新登录的问题。

问题原因

  • 调用runApp重新启动应用会创建新的ProviderScope,导致原有路由栈和状态管理混乱,进而影响后续登录流程。
  • 未重置Riverpod中保存的登录相关状态(如userLogged、forceReload等),即使Firebase Auth已退出,应用仍基于旧状态判断登录状态。

解决方案

步骤1:修复退出登录方法

移除runApp调用,改为重置Riverpod状态并跳转至首页,同时清空路由栈:

修改HomePage中的signOut方法:

Future<void> signOut(BuildContext context) async {
  await FirebaseAuth.instance.signOut();
  // 重置所有登录相关的Riverpod状态
  context.read(userLogged).state = null;
  context.read(forceReload).state = false;
  context.read(userToken).state = '';
  // 跳转至首页并清空路由栈,避免返回原页面
  Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
}

步骤2:实时监听Firebase Auth状态变化

在MyHomePage中使用StreamBuilder监听Firebase Auth的状态变化,替代原有的FutureBuilder,确保UI能实时响应登录/退出状态:

修改MyHomePage的build方法:

@override
Widget build(BuildContext context, watch) {
  return SafeArea(
    child: Scaffold(
      key: scaffoldState,
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/my_bg.png'),
            fit: BoxFit.cover,
          ),
        ),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Container(
              padding: const EdgeInsets.all(16),
              width: MediaQuery.of(context).size.width,
              // 使用StreamBuilder监听auth状态变化
              child: StreamBuilder<User?>(
                stream: FirebaseAuth.instance.authStateChanges(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return Center(child: CircularProgressIndicator());
                  } else {
                    final user = snapshot.data;
                    if (user != null) {
                      // 用户已登录,自动触发登录状态检查
                      WidgetsBinding.instance.addPostFrameCallback((_) async {
                        await checkLoginState(context, true, scaffoldState);
                      });
                      return Container();
                    } else {
                      // 用户未登录,显示登录按钮
                      return ElevatedButton.icon(
                        onPressed: () => processLogin(context),
                        icon: Icon(Icons.phone, color: Colors.white),
                        label: Text(
                          'Login with phone',
                          style: TextStyle(color: Colors.white),
                        ),
                        style: ButtonStyle(
                          backgroundColor: MaterialStateProperty.all(Colors.black),
                        ),
                      );
                    }
                  }
                },
              ),
            ),
          ],
        ),
      ),
    ),
  );
}

步骤3:优化checkLoginState逻辑

确保checkLoginState在用户退出后能正确重置状态,避免forceReload导致的流程阻塞:

修改checkLoginState方法中的条件判断:

Future<LOGIN_STATE> checkLoginState(BuildContext context, bool fromLogin,
    GlobalKey<ScaffoldState> scaffoldState) async {
  final user = FirebaseAuth.instance.currentUser;
  if (user == null) {
    return LOGIN_STATE.NOT_LOGIN;
  }
  
  // 无论forceReload状态如何,登录时都重新获取用户数据
  try {
    var token = await user.getIdToken();
    context.read(userToken).state = token;
    CollectionReference userRef = FirebaseFirestore.instance.collection('User');
    DocumentSnapshot snapshotUser = await userRef.doc(user.phoneNumber).get();
    
    if (snapshotUser.exists) {
      Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
    } else {
      // 弹出信息填写弹窗,逻辑保持不变
      var nameController = TextEditingController();
      var addressController = TextEditingController();
      Alert(
        context: context,
        title: 'Update data',
        content: Column(
          children: [
            TextField(
              decoration: InputDecoration(
                icon: Icon(Icons.account_circle), labelText: 'Имя'),
              controller: nameController,
            ),
            TextField(
              decoration: InputDecoration(
                icon: Icon(Icons.home), labelText: 'Адрес'),
              controller: addressController,
            )
          ],
        ),
        buttons: [
          DialogButton(
            child: Text('Cancel'),
            onPressed: () => Navigator.pop(context),
          ),
          DialogButton(
            child: Text('Update'),
            onPressed: () {
              userRef.doc(user.phoneNumber).set({
                'name': nameController.text,
                'address': addressController.text
              }).then((value) async {
                Navigator.pop(context);
                ScaffoldMessenger.of(scaffoldState.currentContext!)
                    .showSnackBar(SnackBar(content: Text('Update Successful!')));
                await Future.delayed(Duration(seconds: 1), () {
                  Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
                });
              }).catchError((e) {
                Navigator.pop(context);
                ScaffoldMessenger.of(scaffoldState.currentContext!)
                    .showSnackBar(SnackBar(content: Text('$e')));
              });
            },
          ),
        ],
      ).show();
    }
    return LOGIN_STATE.LOGGED;
  } catch (e) {
    print(e);
    return LOGIN_STATE.NOT_LOGIN;
  }
}

修改说明

  1. 移除runApp调用:避免重新初始化应用导致的状态和路由混乱,改用路由跳转并清空栈的方式回到首页。
  2. 重置Riverpod状态:退出时将userLogged、forceReload、userToken等状态重置为初始值,确保下次登录流程不受旧状态影响。
  3. StreamBuilder监听auth状态:实时获取Firebase Auth的登录/退出状态,自动更新UI,无需依赖FutureBuilder的单次判断。
  4. 优化checkLoginState逻辑:移除forceReload的限制,确保每次登录都重新获取用户数据,避免状态残留。

内容的提问来源于stack exchange,提问作者JustAGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:07:34