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

Flutter项目Firebase手机号认证失败,含invalid_grant及组件错误

问题分析与解决办法

一、先搞定looking up a deactivated widget's ancestor is unsafe错误

这个报错本质是组件已经被销毁,你还在拿它的上下文(context)做操作——比如异步请求发完验证码、验证完OTP后直接跳页面或弹提示,但这时候原页面可能已经被移出组件树了。

常用修复思路:

  • 在State类里用mounted属性判断组件是否存活,异步操作完成后先检查mounted,再执行需要上下文的操作(比如跳转、弹SnackBar)。
  • 别在initState里直接用上下文,要延迟执行的话用WidgetsBinding.instance.addPostFrameCallback。
  • 要是用了Provider、Bloc这类状态管理工具,记得在组件销毁时取消订阅。

页面代码具体修改方向:

首页(发送验证码页面)

假设你发送验证码的方法是异步的,改成这样:

// 发送验证码的方法
void sendOTP() async {
  // 先做手机号格式校验
  try {
    await FirebaseAuth.instance.verifyPhoneNumber(
      phoneNumber: phoneController.text,
      verificationCompleted: (PhoneAuthCredential credential) async {
        // 先检查组件是否还挂载
        if (!mounted) return;
        await FirebaseAuth.instance.signInWithCredential(credential);
        // 跳转首页或目标页面
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeScreen()));
      },
      verificationFailed: (FirebaseAuthException e) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.message ?? '验证失败')));
      },
      codeSent: (String verificationId, int? resendToken) {
        if (!mounted) return;
        // 跳转到OTP验证页,传递verificationId
        Navigator.push(context, MaterialPageRoute(builder: (_) => OTPScreen(verificationId: verificationId)));
      },
      codeAutoRetrievalTimeout: (String verificationId) {},
    );
  } catch (e) {
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.toString())));
    }
  }
}

OTP验证页

验证OTP的异步方法里也加上mounted检查:

void verifyOTP() async {
  try {
    PhoneAuthCredential credential = PhoneAuthProvider.credential(
      verificationId: widget.verificationId,
      smsCode: otpController.text,
    );
    await FirebaseAuth.instance.signInWithCredential(credential);
    if (!mounted) return;
    // 登录成功后跳转目标页面
    Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeScreen()));
  } catch (e) {
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('OTP验证失败')));
    }
  }
}

另外,如果页面跳转后未正确销毁,或依赖全局上下文,建议改用GlobalKey获取Scaffold上下文,避免直接使用组件context:

// 在State类中定义
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

// build方法中给Scaffold设置key
Scaffold(
  key: _scaffoldKey,
  // ...其他内容
)

// 弹SnackBar时使用
_scaffoldKey.currentState?.showSnackBar(...)

二、再解决invalid_grant错误

这个报错一般和Firebase认证令牌、配置有关,结合你已配置SHA-1/SHA-256,再排查以下几点:

  • 调试/发布环境SHA值要对应:调试用debug keystore的SHA值,发布用release keystore的,两个都要在Firebase后台配置。
  • 重新下载google-services.json:去Firebase后台重新下载该文件,替换项目中的对应文件,确保包名和SHA值完全匹配。
  • 清除缓存重装应用:令牌过期或无效时,卸载重装应用,或先调用FirebaseAuth.instance.signOut()再重新尝试登录。
  • 检查地区限制:部分地区手机号可能无法接收Firebase验证码,换测试手机号试试,或查看Firebase项目的地区设置。

额外提醒

  • 确保Flutter和Firebase插件版本兼容,查看pubspec.yaml中的firebase_core、firebase_auth,尽量使用稳定版。
  • 测试时用真实设备,模拟器可能存在验证码接收问题。
  • 开启Firebase Auth调试模式,查看更详细的错误日志:
FirebaseAuth.instance.setLoggingEnabled(true);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 02:42:40