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

Flutter实现FirebaseAuth登录错误时显示Snackbar/Dialog

解决FirebaseAuth认证错误在UI层显示Snackbar/Dialog的问题

要实现认证错误的前端提示,需要从状态存储错误信息、错误向上传递、UI监听状态触发提示三个环节改造现有代码,具体步骤如下:


1. 扩展SigninState,新增错误信息字段

原状态仅标记错误状态,无法传递具体错误内容,需要为SigninState添加errorMessage字段,用于存储Firebase返回的错误描述:

part of 'signin_cubit.dart';

enum SigninStatus { initial, submitting, success, error }

class SigninState extends Equatable {
  final String email;
  final String password;
  final SigninStatus status;
  final String? errorMessage; // 新增:存储具体错误信息

  bool get isFormValid => email.isNotEmpty && password.isNotEmpty;

  const SigninState({
    required this.email,
    required this.password,
    required this.status,
    this.errorMessage,
  });

  factory SigninState.initial() {
    return SigninState(
      email: '',
      password: '',
      status: SigninStatus.initial,
      errorMessage: null,
    );
  }

  @override
  bool get stringify => true;

  @override
  List<Object?> get props => [email, password, status, errorMessage]; // 更新props包含新字段

  SigninState copyWith({
    String? email,
    String? password,
    SigninStatus? status,
    String? errorMessage,
  }) {
    return SigninState(
      email: email ?? this.email,
      password: password ?? this.password,
      status: status ?? this.status,
      errorMessage: errorMessage ?? this.errorMessage,
    );
  }
}

2. 修改AuthRepository,抛出错误而非仅打印

原认证函数仅打印错误,需要将错误向上抛出,让Cubit捕获并处理:

Future<User?> signInWithEmailAndPassword({required String email, required String password}) async {
  try {
    final credential = await _firebaseAuth.signInWithEmailAndPassword(
        email: email, password: password);
    final user = _userFromFirebaseUser(credential.user);
    return user;
  } catch (e) {
    rethrow; // 抛出错误,交给上层Cubit处理
  }
}

3. 更新SigninCubit,捕获并存储错误信息

在signInWithCredentials方法中,捕获Firebase错误并提取具体信息,更新到状态中:

void signInWithCredentials() async {
  try {
    emit(state.copyWith(status: SigninStatus.submitting)); // 新增提交中状态,优化用户感知
    await _authRepository.signInWithEmailAndPassword(
        email: state.email, password: state.password);
    emit(
      state.copyWith(status: SigninStatus.success, errorMessage: null),
    );
  } catch (e) {
    // 提取Firebase认证错误信息,默认提示兜底
    String errorMsg = e is FirebaseAuthException 
        ? e.message ?? '登录失败,请重试' 
        : '登录失败,请重试';
    emit(state.copyWith(status: SigninStatus.error, errorMessage: errorMsg));
  }
}

4. 在UI页面监听状态,触发Snackbar/Dialog

在输入框所在页面,使用BlocListener监听SigninState的变化,当状态变为error时,弹出提示:

// 在页面的Widget树中添加BlocListener
BlocListener<SigninCubit, SigninState>(
  listener: (context, state) {
    // 显示错误提示
    if (state.status == SigninStatus.error && state.errorMessage != null) {
      // 方案1:显示Snackbar
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(state.errorMessage!),
          backgroundColor: Colors.red,
          duration: const Duration(seconds: 3),
        ),
      );

      // 方案2:显示Dialog(二选一即可)
      // showDialog(
      //   context: context,
      //   builder: (ctx) => AlertDialog(
      //     title: const Text('登录失败'),
      //     content: Text(state.errorMessage!),
      //     actions: [
      //       TextButton(
      //         onPressed: () => Navigator.pop(ctx),
      //         child: const Text('确定'),
      //       ),
      //     ],
      //   ),
      // );
    }

    // 登录成功后的跳转逻辑
    if (state.status == SigninStatus.success) {
      Navigator.pushReplacementNamed(context, '/home'); // 替换为你的主页路由
    }
  },
  child: // 原页面内容(输入框、按钮等)
)

同时可以优化按钮点击逻辑,先校验表单完整性:

if (tabController.index == 3) {
  final signinState = context.read<SigninCubit>().state;
  if (signinState.isFormValid) {
    context.read<SigninCubit>().signInWithCredentials();
  } else {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请填写完整的邮箱和密码')),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 03:16:04