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
相关产品推荐
相关产品推荐

