在Flutter的adsearch.dart中实现Dialog式Firebase OTP认证
实现Dialog形式的Firebase OTP认证流程(adsearch.dart)
以下是完整的实现方案,直接在adsearch.dart文件中完成Dialog式OTP登录,并在userAuthentication函数中调用:
1. 前置配置
确保项目已集成Firebase Auth,并在Firebase控制台启用Phone认证,同时在pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter firebase_auth: ^4.17.0
2. 实现Dialog组件
在adsearch.dart中添加以下代码,包含手机号输入页、OTP验证页的切换逻辑:
import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; // 显示OTP认证Dialog void _showPhoneAuthDialog(BuildContext context) { final TextEditingController _phoneController = TextEditingController(); final TextEditingController _otpController = TextEditingController(); String? _verificationId; int _currentPage = 0; // 0: 手机号输入页, 1: OTP验证页 bool _isLoading = false; showDialog( context: context, barrierDismissible: false, builder: (context) => StatefulBuilder( builder: (context, setState) => AlertDialog( title: Text(_currentPage == 0 ? '登录账号' : '输入验证码'), content: _isLoading ? const Center(child: CircularProgressIndicator()) : _currentPage == 0 ? TextField( controller: _phoneController, keyboardType: TextInputType.phone, decoration: const InputDecoration( hintText: '请输入手机号(如+86138xxxxxxx)', prefixIcon: Icon(Icons.phone), ), ) : Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _otpController, keyboardType: TextInputType.number, maxLength: 6, decoration: const InputDecoration( hintText: '请输入6位验证码', prefixIcon: Icon(Icons.sms), ), ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () => setState(() => _currentPage = 0), child: const Text('修改手机号'), ), TextButton( onPressed: _verificationId == null ? null : () => _resendOTP(setState, context), child: const Text('重新发送'), ), ], ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), ElevatedButton( onPressed: _isLoading ? null : () => _handleAction(setState, context), child: Text(_currentPage == 0 ? '发送验证码' : '验证登录'), ), ], ), ), ); // 处理页面按钮点击逻辑 void _handleAction(StateSetter setState, BuildContext context) async { setState(() => _isLoading = true); try { if (_currentPage == 0) { // 发送OTP await FirebaseAuth.instance.verifyPhoneNumber( phoneNumber: _phoneController.text.trim(), verificationCompleted: (PhoneAuthCredential credential) async { // 自动验证(部分设备支持) await FirebaseAuth.instance.signInWithCredential(credential); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('登录成功')), ); }, verificationFailed: (FirebaseAuthException e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('发送失败:${e.message}')), ); }, codeSent: (String verificationId, int? resendToken) { setState(() { _isLoading = false; _verificationId = verificationId; _currentPage = 1; }); }, codeAutoRetrievalTimeout: (String verificationId) { _verificationId = verificationId; }, ); } else { // 验证OTP final credential = PhoneAuthProvider.credential( verificationId: _verificationId!, smsCode: _otpController.text.trim(), ); await FirebaseAuth.instance.signInWithCredential(credential); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('登录成功')), ); } } catch (e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('操作失败:${e.toString()}')), ); } } // 重新发送OTP void _resendOTP(StateSetter setState, BuildContext context) async { setState(() => _isLoading = true); try { await FirebaseAuth.instance.verifyPhoneNumber( phoneNumber: _phoneController.text.trim(), verificationCompleted: (PhoneAuthCredential credential) async { await FirebaseAuth.instance.signInWithCredential(credential); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('登录成功')), ); }, verificationFailed: (FirebaseAuthException e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('重新发送失败:${e.message}')), ); }, codeSent: (String verificationId, int? resendToken) { setState(() { _isLoading = false; _verificationId = verificationId; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('验证码已重新发送')), ); }, codeAutoRetrievalTimeout: (String verificationId) { _verificationId = verificationId; }, ); } catch (e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('重新发送失败:${e.toString()}')), ); } } }
3. 在userAuthentication函数中调用Dialog
在adsearch.dart的userAuthentication函数中直接调用上述Dialog:
void userAuthentication(BuildContext context) { // 触发OTP认证Dialog _showPhoneAuthDialog(context); }
关键功能说明
- 页面切换:通过
_currentPage变量控制显示手机号输入页或OTP验证页 - 加载状态:操作过程中显示
CircularProgressIndicator,防止重复点击 - 错误处理:发送/验证失败时通过SnackBar提示具体错误信息
- 额外选项:OTP页提供「修改手机号」返回上一页,「重新发送」再次获取验证码
- 自动验证:支持部分设备的自动验证码填充与登录
内容的提问来源于stack exchange,提问作者Yahya
相关产品推荐
相关产品推荐

