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

使用sms_autofill包时Firebase OTP自动填充失效问题

解决Flutter中Firebase Auth OTP无法自动填充到PinFieldAutoFill的问题

问题诊断

从你的代码来看,存在几个关键问题导致OTP无法自动填充:

  • 控制器销毁逻辑错误,未正确释放verifyCodeController
  • 缺少应用签名配置,sms_autofill无法识别Firebase发送的验证短信
  • 监听逻辑未绑定到输入框的控制器更新

分步解决方案

1. 修正控制器销毁逻辑

在dispose方法中,你错误地创建了一个新的TextEditingController并销毁,而非使用已声明的verifyCodeController:

@override
void dispose() {
  super.dispose();
  verifyCodeController.dispose(); // 修正:销毁正确的控制器
  SmsAutoFill().unregisterListener();
}

2. 获取并配置应用签名

sms_autofill依赖应用签名来监听目标短信,需要将签名配置到Firebase控制台:

  • 在initState中临时添加代码获取签名:
    @override
    void initState() {
      super.initState();
      _getAppSignature();
      _listenForCode();
    }
    
    _getAppSignature() async {
      String signature = await SmsAutoFill().getAppSignature();
      print("App Signature: $signature");
    }
    
  • 运行App后在控制台复制签名,进入Firebase控制台 → 项目设置 → 应用 → 添加签名哈希,粘贴获取到的签名值。

3. 添加必要权限

  • Android:在android/app/src/main/AndroidManifest.xml中添加权限:
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    
  • iOS:在ios/Runner/Info.plist中添加权限描述:
    <key>NSMessagesUsageDescription</key>
    <string>需要读取短信以自动填充验证码</string>
    

4. 优化OTP监听逻辑

修改_listenForCode方法,将获取到的OTP直接同步到控制器:

_listenForCode() async {
  await SmsAutoFill().listenForCode();
  // 监听验证码更新并同步到输入框
  SmsAutoFill().codeUpdated.listen((code) {
    if (code != null && code.length == 6) {
      setState(() {
        verifyCodeController.text = code;
      });
    }
  });
  print("OTP listen Called");
}

5. 确保短信格式符合要求

Firebase发送的验证短信需包含连续的6位数字验证码,例如:

Your verification code for FirebasePractice is: 123456

sms_autofill默认会匹配短信中4-6位的连续数字,确保验证码无额外分隔符。

修正后的完整代码

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'package:FirebasePractice/Ui/posts/post_screen.dart';
import 'package:FirebasePractice/Utils/Utils.dart';
import 'package:FirebasePractice/widgets/roundbutton.dart';

class VerifyCode extends StatefulWidget {
  final String verificationId;

  const VerifyCode({Key? key, required this.verificationId}) : super(key: key);

  @override
  State<VerifyCode> createState() => _VerifyCodeState();
}

class _VerifyCodeState extends State<VerifyCode> {
  bool loading = false;
  final verifyCodeController = TextEditingController();
  final auth = FirebaseAuth.instance;

  @override
  void initState() {
    super.initState();
    _getAppSignature();
    _listenForCode();
  }

  @override
  void dispose() {
    super.dispose();
    verifyCodeController.dispose();
    SmsAutoFill().unregisterListener();
  }

  _getAppSignature() async {
    String signature = await SmsAutoFill().getAppSignature();
    print("App Signature: $signature");
  }

  _listenForCode() async {
    await SmsAutoFill().listenForCode();
    SmsAutoFill().codeUpdated.listen((code) {
      if (code != null && code.length == 6) {
        setState(() {
          verifyCodeController.text = code;
        });
      }
    });
    print("OTP listen Called");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Verify"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            const SizedBox(height: 20),
            PinFieldAutoFill(
              codeLength: 6,
              autoFocus: true,
              controller: verifyCodeController,
              onCodeSubmitted: (code) {
                print("onCodeSubmitted $code");
              },
              onCodeChanged: (val) {
                print("onCodeChanged $val");
              },
              decoration: UnderlineDecoration(
                textStyle: const TextStyle(fontSize: 20, color: Colors.black),
                colorBuilder: const FixedColorBuilder(Colors.black),
              ),
            ),
            const SizedBox(height: 50),
            Roundbutton(
              title: "Verify",
              loading: loading,
              onTap: () async {
                setState(() {
                  loading = true;
                });
                final credential = PhoneAuthProvider.credential(
                  verificationId: widget.verificationId,
                  smsCode: verifyCodeController.text.toString(),
                );
                try {
                  await auth.signInWithCredential(credential);
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Postscreen()),
                  );
                } catch (e) {
                  setState(() {
                    loading = false;
                  });
                  Utils().toastmessage(e.toString());
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:14:51