Flutter Firebase电话认证报错:invalid-verification-id 求助
问题排查与修复方案
核心问题分析
你遇到的[firebase_auth/invalid-verification-id]错误,核心由以下代码问题导致:
- 弹窗中的OTP输入框未绑定
otpController,导致始终获取不到用户输入的验证码,Firebase因无效验证码返回关联的验证ID错误提示 - 闭包作用域内的变量同名冲突,
codeSent回调的参数verificationId与State成员变量重名,可能导致引用混乱 - 未处理异步登录异常,且跳转页面时未先关闭弹窗,引发上下文逻辑错误
修复后的完整代码
import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:otp_login/OTP_Successful.dart'; class SendOtp extends StatefulWidget { const SendOtp({Key? key}) : super(key: key); @override State<SendOtp> createState() => _SendOtpState(); } class _SendOtpState extends State<SendOtp> { final TextEditingController phoneController = TextEditingController(); final TextEditingController otpController = TextEditingController(); final FirebaseAuth auth = FirebaseAuth.instance; String? verificationId; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Send OTP"), ), body: Center( child: ListView( padding: const EdgeInsets.symmetric(horizontal: 20), children: [ TextFormField( controller: phoneController, decoration: const InputDecoration(labelText: "Enter Phone Number"), keyboardType: TextInputType.phone, ), const SizedBox(height: 20), ElevatedButton( onPressed: () async { await FirebaseAuth.instance.verifyPhoneNumber( phoneNumber: phoneController.text, verificationCompleted: (PhoneAuthCredential credential) async { await auth.signInWithCredential(credential); if (mounted) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const OtpSuccessful()), ); } }, verificationFailed: (FirebaseAuthException e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("验证失败: ${e.message}")), ); }, codeSent: (String verificationId, int? resendToken) { setState(() { this.verificationId = verificationId; }); _showOtpDialog(); }, codeAutoRetrievalTimeout: (String verificationId) { setState(() { this.verificationId = verificationId; }); }, ); }, child: const Text("Send OTP"), ) ], ), ), ); } void _showOtpDialog() { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Enter OTP'), content: TextFormField( controller: otpController, decoration: const InputDecoration(labelText: "OTP"), keyboardType: TextInputType.number, maxLength: 6, ), actions: [ ElevatedButton( onPressed: () async { if (verificationId == null || otpController.text.length != 6) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("请输入有效的6位OTP")), ); return; } try { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId!, smsCode: otpController.text, ); await auth.signInWithCredential(credential); if (mounted) { Navigator.pop(context); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const OtpSuccessful()), ); } } on FirebaseAuthException catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("登录失败: ${e.message}")), ); } }, child: const Text("OK"), ) ], ); }, ); } }
关键修复点说明
- 绑定OTP控制器:为弹窗输入框添加
controller: otpController,确保能正确获取用户输入的验证码 - 分离弹窗逻辑:将弹窗提取为单独方法,避免闭包作用域内的变量同名冲突,确保使用State类的
verificationId成员变量 - 添加输入校验:检查OTP长度是否为6位,提前拦截无效输入
- 异常捕获与提示:用
try-catch包裹登录逻辑,捕获Firebase异常并给出明确提示 - 优化页面跳转:先关闭弹窗再跳转到成功页面,避免上下文逻辑混乱
- 完善自动验证:在
verificationCompleted回调中处理自动登录场景,并用mounted判断组件状态,避免空上下文错误
内容的提问来源于stack exchange,提问作者VIKAS VERMA
相关产品推荐
相关产品推荐

