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

Flutter OTP自动填充后无法验证 求验证按钮事件实现代码

问题根因
  • 自动填充后校验失败的核心原因:sms_autofill监听到短信验证码后,仅向输入框绑定的TextEditingController写入值完成UI填充,该操作不会触发输入组件的onChanged回调,状态类中存储OTP值的变量未同步更新,点击按钮时读取到的仍是空值/初始值,无法通过Firebase Auth校验。
  • 手动输入场景下每次字符输入都会触发onChanged回调,状态变量与输入框内容实时同步,因此校验流程正常。
Verify OTP按钮onPressed正确实现

前置配置(必须做,否则自动填充值不同步)

先在短信监听逻辑中补全状态同步代码,放在页面initState生命周期中执行:

late TextEditingController otpController;
String currentOtp = "";
bool isLoading = false;

@override
void initState() {
  super.initState();
  otpController = TextEditingController();
  _listenSmsCode();
}

void _listenSmsCode() async {
  await SmsAutoFill().listenForCode;
  SmsAutoFill().code.listen((code) {
    setState(() {
      // 填充输入框的同时同步更新状态变量
      otpController.text = code;
      currentOtp = code;
    });
  });
}

按钮点击事件完整逻辑

ElevatedButton(
  onPressed: () async {
    // 收起键盘
    FocusScope.of(context).unfocus();
    // 核心:直接从controller取最新值做兜底,不依赖单独存储的状态变量
    final inputOtp = otpController.text.trim();
    
    // 基础格式校验
    if (inputOtp.length != 6) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text("请输入完整6位验证码"))
      );
      return;
    }

    setState(() {
      isLoading = true;
    });

    try {
      // 复用手动输入页的Firebase Auth校验逻辑,不要做任何修改
      PhoneAuthCredential credential = PhoneAuthProvider.credential(
        verificationId: widget.verificationId,
        smsCode: inputOtp
      );
      await FirebaseAuth.instance.signInWithCredential(credential);
      
      // 校验成功跳转
      if (mounted) {
        Navigator.pushReplacementNamed(context, '/home');
      }
    } on FirebaseAuthException catch (e) {
      String errorMsg = "验证失败,请重试";
      if (e.code == 'invalid-verification-code') {
        errorMsg = "验证码无效,请检查后重新输入";
      } else if (e.code == 'session-expired') {
        errorMsg = "验证码已过期,请重新获取";
      }
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text(errorMsg))
        );
      }
    } finally {
      if (mounted) {
        setState(() {
          isLoading = false;
        });
      }
    }
  },
  child: isLoading 
    ? const SizedBox(
        height: 20, width: 20,
        child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)
      )
    : const Text("Verify OTP"),
)
避坑注意项
  • 页面销毁时必须注销短信监听、释放controller,避免内存泄漏:
@override
void dispose() {
  SmsAutoFill().unregisterListener();
  otpController.dispose();
  super.dispose();
}
  • 如果使用pinput/pin_code_fields等第三方验证码输入组件,直接绑定上述otpController即可,自动填充时组件会自动同步内容,无需额外处理光标位置。
  • 所有输入值校验统一在按钮点击时从controller读取,不要完全依赖onChanged回调传值,可覆盖所有自动填充、粘贴等非手动输入场景的值不同步问题。

内容的提问来源于stack exchange,提问作者sr2k23

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:22:09