Flutter中Firebase手机号认证OTP校验问题求助
Flutter Firebase 手机号认证 OTP 校验问题解决方案
修正认证服务类(FirebaseAuthService)
改用Firebase Auth v2的signInWithPhoneNumber方法(比旧版回调方式更易维护),封装发送验证码与OTP校验逻辑:
import 'package:firebase_auth/firebase_auth.dart'; class FirebaseAuthService { final FirebaseAuth _auth = FirebaseAuth.instance; // 发送手机号验证码 Future<String?> sendVerificationCode(String phoneNumber) async { try { // Web端需配置Recaptcha,移动端可省略该参数 final confirmationResult = await _auth.signInWithPhoneNumber( phoneNumber, RecaptchaVerifier( container: 'recaptcha-container', size: RecaptchaVerifierSize.compact, theme: RecaptchaVerifierTheme.light, ), ); return confirmationResult.verificationId; } catch (e) { print('发送验证码失败: ${e.toString()}'); return null; } } // 校验OTP验证码 Future<UserCredential?> verifyOTP(String verificationId, String smsCode) async { try { final credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: smsCode, ); return await _auth.signInWithCredential(credential); } catch (e) { print('OTP校验失败: ${e.toString()}'); return null; } } }
修正OTP页面(OTPView)调用逻辑
确保正确存储verificationId,并规范使用async/await处理异步操作:
import 'package:flutter/material.dart'; import 'firebase_auth_service.dart'; class OTPView extends StatefulWidget { final String phoneNumber; // 传入带国际区号的手机号,如+8613xxxxxxxxx const OTPView({super.key, required this.phoneNumber}); @override State<OTPView> createState() => _OTPViewState(); } class _OTPViewState extends State<OTPView> { final FirebaseAuthService _authService = FirebaseAuthService(); final TextEditingController _otpController = TextEditingController(); String? _verificationId; @override void initState() { super.initState(); // 页面初始化时自动发送验证码 _sendVerificationCode(); } Future<void> _sendVerificationCode() async { final verificationId = await _authService.sendVerificationCode(widget.phoneNumber); if (verificationId != null) { setState(() => _verificationId = verificationId); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('验证码发送失败,请检查手机号格式或网络')), ); } } Future<void> _onVerifyPressed() async { if (_verificationId == null || _otpController.text.length != 6) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请输入有效的6位验证码')), ); return; } final credential = await _authService.verifyOTP( _verificationId!, _otpController.text.trim(), // 去除可能的空格 ); if (credential != null) { // 校验成功,跳转至主页或业务页面 Navigator.pushReplacementNamed(context, '/home'); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('验证码无效,请重新输入')), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('验证手机号')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( controller: _otpController, keyboardType: TextInputType.number, maxLength: 6, textAlign: TextAlign.center, decoration: const InputDecoration( labelText: '输入6位验证码', border: OutlineInputBorder(), ), ), const SizedBox(height: 24), ElevatedButton( onPressed: _onVerifyPressed, child: const Text('验证'), ), ], ), ), ); } }
常见问题排查
- 手机号格式:必须携带国际区号(如
+86),否则Firebase无法识别 - Firebase配置:
- Android:在控制台添加SHA-1、SHA-256指纹,确保
google-services.json已正确放入项目 - iOS:配置APNs权限,确保
GoogleService-Info.plist已添加到Xcode项目
- Android:在控制台添加SHA-1、SHA-256指纹,确保
- 验证码有效期:Firebase验证码有效期为5分钟,超时需重新发送
- 错误定位:打印错误日志,根据错误码排查(如
invalid-verification-code表示验证码无效,session-expired表示会话过期)
内容的提问来源于stack exchange,提问作者Adam A.
相关产品推荐
相关产品推荐

