Google Play应用中Firebase短信验证码过期问题的代码修复方法
问题:Google Play发布后手机号认证触发Session过期错误
应用发布至Google Play商店后,用户输入手机号验证码时出现如下错误:
[firebase_auth/session-expired] The SMS code has expired. Please re-send the verification code to try again.
当前代码
Code 1. 验证页面
Future<void> verifyOtp(BuildContext context, String userOtp) async { final authProvider = Provider.of<AuthViewModel>(context, listen: false); await authProvider.verifyOtp( context: context, verificationId: widget.verificationId, userOtp: userOtp, onSuccess: () async { // 检查用户是否存在于数据库 bool userExists = await authProvider.checkExistingUser(); if (userExists) { // 用户已存在 await authProvider.getDataFromFirestore(); await authProvider.saveDataToSP(); await authProvider.setSignIn(); if (!mounted) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => HomeMain()), (route) => false); } else { // 新用户 if (!mounted) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => GenderSelection()), (route) => false); } }); }
Code 2. 认证提供者
// 手机号登录 void signInWithPhone(BuildContext context, String phoneNumber) async { try { await _auth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { await _auth.signInWithCredential(credential); }, verificationFailed: (FirebaseAuthException e) { throw Exception(e.message); }, codeSent: (verificationId, forceRecendingToken) async { Navigator.push( context, MaterialPageRoute( builder: (context) => InputVerificationNumber( verificationId: verificationId, ), ), ); }, codeAutoRetrievalTimeout: (String verificationId) {}, ); } on FirebaseAuthException catch (e) { showAlertDialog( context: context, title: 'Error', message: e.message ?? '에러가 발생했습니다. 개발팀에 문의해주세요.'); } } // 验证验证码 Future<void> verifyOtp({ required BuildContext context, required String verificationId, required String userOtp, required Function onSuccess, }) async { _isLoading = true; notifyListeners(); try { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: userOtp, ); User? user = (await _auth.signInWithCredential(credential)).user; if (user != null) { _uid = user.uid; await onSuccess(); } _isLoading = false; notifyListeners(); } on FirebaseAuthException catch (e) { _isLoading = false; notifyListeners(); await showOkAlertDialog( context: context, message: '로그인 과정에서 문제가 발생했습니다. \n$e'); } }
代码修改方案
1. 完善认证提供者的会话过期与重发逻辑
在AuthViewModel中添加状态保存与超时处理:
// 新增变量保存重发令牌与手机号 String? _forceResendingToken; String? _currentPhoneNumber; // 修改手机号登录方法,支持重发验证码 void signInWithPhone(BuildContext context, String phoneNumber, {bool isResend = false}) async { _currentPhoneNumber = phoneNumber; try { await _auth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { await _auth.signInWithCredential(credential); }, verificationFailed: (FirebaseAuthException e) { throw Exception(e.message); }, codeSent: (verificationId, forceRecendingToken) { _forceResendingToken = forceRecendingToken; if (!isResend) { Navigator.push( context, MaterialPageRoute( builder: (context) => InputVerificationNumber( verificationId: verificationId, authProvider: this, phoneNumber: phoneNumber, ), ), ); } else { notifyListeners(); showOkAlertDialog(context: context, message: "验证码已重新发送"); } }, // 会话超时主动提示用户重发 codeAutoRetrievalTimeout: (String verificationId) { showOkAlertDialog( context: context, message: "验证码已过期,请重新获取", onPressed: () => signInWithPhone(context, phoneNumber, isResend: true), ); }, forceResendingToken: isResend ? _forceResendingToken : null, ); } on FirebaseAuthException catch (e) { showAlertDialog( context: context, title: '错误', message: e.message ?? '发生错误,请联系开发团队'); } } // 修改验证码验证的错误处理 Future<void> verifyOtp({ required BuildContext context, required String verificationId, required String userOtp, required Function onSuccess, }) async { _isLoading = true; notifyListeners(); try { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: userOtp, ); User? user = (await _auth.signInWithCredential(credential)).user; if (user != null) { _uid = user.uid; await onSuccess(); } _isLoading = false; notifyListeners(); } on FirebaseAuthException catch (e) { _isLoading = false; notifyListeners(); String message = '登录过程中出现问题。'; if (e.code == 'session-expired') { message = "验证码已过期,请重新获取"; } else { message += '\n$e'; } await showOkAlertDialog( context: context, message: message, onPressed: e.code == 'session-expired' ? () => signInWithPhone(context, _currentPhoneNumber!) : null, ); } }
2. 更新验证页面,支持手动重发验证码
修改页面参数并添加重发按钮:
class InputVerificationNumber extends StatefulWidget { final String verificationId; final AuthViewModel authProvider; final String phoneNumber; const InputVerificationNumber({ super.key, required this.verificationId, required this.authProvider, required this.phoneNumber, }); @override State<InputVerificationNumber> createState() => _InputVerificationNumberState(); } // 在页面build方法中添加重发按钮 @override Widget build(BuildContext context) { return Scaffold( // 原有布局... body: Column( // 原有组件... children: [ // 验证码输入框... TextButton( onPressed: () => widget.authProvider.signInWithPhone(context, widget.phoneNumber, isResend: true), child: const Text("重新发送验证码"), ), ], ), ); }
内容的提问来源于stack exchange,提问作者HappyCoding
相关产品推荐
相关产品推荐

