使用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
相关产品推荐
相关产品推荐

