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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:40:03