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

Flutter Riverpod 1.0中暴露Firebase AuthService对象应使用哪种Provider?

Flutter + Riverpod 实现Firebase手机号认证状态管理

核心思路

你现有的AuthService类状态变更默认无法被UI监听,我们通过Riverpod的Notifier封装认证状态,状态变更时自动通知UI刷新,无需额外实现监听回调。

前置要求

你已经完成Riverpod基础配置:根组件包裹ProviderScope,已引入Flutter Riverpod依赖。

步骤1:补全原有AuthService的getter

先在你提供的AuthService类中增加codeSent的对外暴露:

class AuthService {
  // ... 原有代码不变
  // 新增这行
  bool get codeSent => _codeSent;
}

步骤2:定义Riverpod Provider监听状态

方案A:全状态管理(推荐)

统一管理加载、验证码已发送、验证成功、错误等全链路状态,适配绝大多数业务场景:

import 'package:riverpod/riverpod.dart';
import 'package:firebase_auth/firebase_auth.dart';

// 认证状态枚举
enum AuthStatus { initial, loading, codeSent, verified, error }

class AuthNotifier extends Notifier<AuthStatus> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  String _verificationId = '';
  int? _resendToken;
  // 错误信息可选,用于UI展示报错
  String? errorMessage;

  @override
  AuthStatus build() {
    return AuthStatus.initial;
  }

  // 监听Firebase登录态变更
  Stream<User?> authStateChanges() => _auth.authStateChanges();
  User? get currentUser => _auth.currentUser;

  // 发送验证码
  Future<void> verifyPhoneNumber(String phoneNumber) async {
    state = AuthStatus.loading;
    errorMessage = null;
    try {
      await _auth.verifyPhoneNumber(
        phoneNumber: phoneNumber,
        verificationCompleted: (PhoneAuthCredential credential) async {
          await _auth.signInWithCredential(credential);
          state = AuthStatus.verified;
        },
        verificationFailed: (FirebaseAuthException e) {
          errorMessage = e.message;
          state = AuthStatus.error;
        },
        codeSent: (String verificationId, int? resendToken) {
          _verificationId = verificationId;
          _resendToken = resendToken;
          state = AuthStatus.codeSent;
        },
        codeAutoRetrievalTimeout: (String verificationId) {
          _verificationId = verificationId;
        },
        timeout: const Duration(seconds: 60),
      );
    } catch (e) {
      errorMessage = e.toString();
      state = AuthStatus.error;
    }
  }

  // 验证码登录
  Future<void> signWithOtp(String otp) async {
    state = AuthStatus.loading;
    try {
      final credential = PhoneAuthProvider.credential(
        verificationId: _verificationId,
        smsCode: otp,
      );
      await _auth.signInWithCredential(credential);
      state = AuthStatus.verified;
    } on FirebaseAuthException catch (e) {
      errorMessage = e.message;
      state = AuthStatus.error;
    }
  }

  // 登出
  Future<void> signOut() async {
    try {
      await _auth.signOut();
      state = AuthStatus.initial;
    } catch (e) {
      errorMessage = e.toString();
    }
  }
}

// 全局Provider
final authNotifierProvider = NotifierProvider<AuthNotifier, AuthStatus>(AuthNotifier.new);

方案B:仅监听codeSent布尔状态(最小改动)

如果你只需要单独监听验证码是否发送的状态,不需要其他业务状态管理,可以用最小改动实现:

import 'package:riverpod/riverpod.dart';

class CodeSentNotifier extends Notifier<bool> {
  final AuthService _authService = AuthService();

  @override
  bool build() => false;

  Future<void> sendVerificationCode(String phone) async {
    await _authService.verifyPhoneNumber(phone);
    state = _authService.codeSent;
  }
}

final codeSentProvider = NotifierProvider<CodeSentNotifier, bool>(CodeSentNotifier.new);

步骤3:UI层监听状态实现交互

以全状态管理方案为例,UI层直接监听Provider状态自动刷新:

import 'package:flutter_riverpod/flutter_riverpod.dart';

class PhoneAuthScreen extends ConsumerWidget {
  const PhoneAuthScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final authStatus = ref.watch(authNotifierProvider);
    final authNotifier = ref.read(authNotifierProvider.notifier);

    return Scaffold(
      body: switch(authStatus) {
        // 初始状态:展示手机号输入页
        AuthStatus.initial => PhoneInputView(
          onSubmit: (phone) => authNotifier.verifyPhoneNumber(phone),
        ),
        // 加载中:展示加载动画
        AuthStatus.loading => const Center(child: CircularProgressIndicator()),
        // 验证码已发送:展示OTP输入页,对应你需要的codeSent状态
        AuthStatus.codeSent => OtpInputView(
          onSubmit: (otp) => authNotifier.signWithOtp(otp),
        ),
        // 验证成功:跳转到主页
        AuthStatus.verified => const HomeScreen(),
        // 出错:展示错误提示
        AuthStatus.error => ErrorTipView(
          msg: authNotifier.errorMessage,
          onRetry: () => authNotifier.verifyPhoneNumber(/* 重试手机号 */),
        ),
      }
    );
  }
}

可选:全局登录态监听

可以单独定义StreamProvider监听Firebase的登录态,自动处理登录/未登录的页面跳转:

final authStateProvider = StreamProvider<User?>((ref) {
  return ref.watch(authNotifierProvider.notifier).authStateChanges();
});

// 根路由页直接监听登录态
class RootPage extends ConsumerWidget {
  const RootPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final authState = ref.watch(authStateProvider);
    return authState.when(
      loading: () => const SplashScreen(),
      data: (user) => user == null ? const PhoneAuthScreen() : const HomeScreen(),
      error: (e, stackTrace) => const ErrorScreen(),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 17:54:05