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

Flutter中使用Bloc实现Firebase OTP认证时遇状态更新错误

问题解决指南

错误原因

你遇到的问题核心是:Firebase verifyPhoneNumber的回调函数(如codeSent、verificationFailed)会在Bloc事件处理函数_verifyPhoneNumber执行完毕后才触发,此时Bloc的emit已经被标记为完成状态,再调用emit就会违反Bloc的状态更新规则,触发你看到的错误提示。


一、修复Bloc事件处理中的emit问题

修改_verifyPhoneNumber方法,在每个回调里调用emit前先检查emit.isDone,确保当前事件处理上下文仍有效:

void _verifyPhoneNumber(LoginInSubmittedEvent event, Emitter<SignInState> emit) async {
  String phone = "+91${event.phoneNumber}";
  try {
    emit(SignInLoadingState());
    await firebaseAuth.verifyPhoneNumber(
      phoneNumber: phone,
      verificationCompleted: (PhoneAuthCredential credential) {
        // 先确认emit未完成再更新状态
        if (!emit.isDone) {
          emit(SignInCompletedState(credential));
        }
      },
      verificationFailed: (FirebaseAuthException e) {
        if (!emit.isDone) {
          emit(SignInErrorState(e.toString()));
        }
      },
      codeSent: (String verificationId, int? resendToken) {
        if (!emit.isDone) {
          emit(SignInValidateState(verificationId, resendToken));
        }
      },
      codeAutoRetrievalTimeout: (String verificationId) {
        if (!emit.isDone) {
          emit(SignInTimeoutState(verificationId));
        }
      },
    );
  } catch (e) {
    if (!emit.isDone) {
      emit(SignInErrorState(e.toString()));
    }
  }
}

注:回调函数无需加async,去掉多余的异步标记可避免上下文冲突。


二、修复UI中状态检查的问题

你在按钮onPressed里同步检查state是无效的——Bloc状态更新是异步的,点击按钮后立即检查时,状态还未完成更新。正确做法是用BlocListener或BlocBuilder监听状态变化:

方案1:用BlocListener处理状态副作用(如打印日志、跳转页面)

BlocListener<SignInBloc, SignInState>(
  listener: (context, state) {
    if (state is SignInLoadingState) {
      debugPrint('Loading State');
    } else if (state is SignInErrorState) {
      debugPrint('Error: ${state.errorMessage}');
    } else if (state is SignInValidateState) {
      debugPrint('OTP SENT State');
      // 此处可添加跳转到OTP输入页等逻辑
    } else if (state is SignInTimeoutState) {
      debugPrint('TimeOut State');
    }
  },
  child: TextButton(
    onPressed: () {
      const phoneNumber = '3453453252';
      BlocProvider.of<SignInBloc>(context).add(LoginInSubmittedEvent(phoneNumber));
    },
    child: Text(
      'Get Otp',
      style: AppTextStyles.backNextBtnTextStyle,
    ),
  ),
)

方案2:用BlocBuilder动态更新UI(如显示加载状态)

BlocBuilder<SignInBloc, SignInState>(
  builder: (context, state) {
    // 加载状态时显示进度指示器
    if (state is SignInLoadingState) {
      return const CircularProgressIndicator();
    }
    return TextButton(
      onPressed: () {
        const phoneNumber = '3453453252';
        BlocProvider.of<SignInBloc>(context).add(LoginInSubmittedEvent(phoneNumber));
      },
      child: Text(
        'Get Otp',
        style: AppTextStyles.backNextBtnTextStyle,
      ),
    );
  },
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:35:30