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

Flutter应用部分Google OAuth认证用户数据未写入Firestore问题排查

问题排查与修复方案

1. 缺少错误捕获,写入失败无日志

checkUser()函数没有异常捕获逻辑,任何步骤(网络波动、FCM Token获取失败、权限问题)出错都会静默失败,无法定位原因。

修复:
给checkUser()添加try-catch块,打印错误信息:

Future<void> checkUser() async {
  try {
    // 原逻辑代码
  } catch (e) {
    if (kDebugMode) {
      print('用户数据写入失败: $e');
    }
  }
}

2. 强制解包currentUser引发崩溃

虽然路由中判断了认证状态,但authStateChanges的流可能存在短暂的null状态(如网络延迟同步),强制解包FirebaseAuth.instance.currentUser!会直接崩溃,中断写入流程。

修复:
先判断用户是否为null,再执行后续逻辑:

final user = FirebaseAuth.instance.currentUser;
if (user == null) return; // 避免崩溃,直接返回

3. 邮箱大小写不一致导致查询误判

Google认证返回的邮箱可能存在大小写差异,而Firestore的where查询区分大小写,会导致误判用户不存在/已存在,影响写入逻辑。

修复:
统一将邮箱转为小写存储和查询:

// 查询时转小写
var collection = FirebaseFirestore.instance
    .collection('users')
    .where('gmail', isEqualTo: user.email?.toLowerCase());

// 存储时也转小写
final userInformation = {
  // ...其他字段
  'gmail': user.email?.toLowerCase(),
};

4. FCM Token获取失败中断写入流程

FirebaseMessaging.instance.getToken()可能返回null或抛出异常,导致后续的set操作无法执行,整个写入流程失败。

修复:
单独捕获Token获取的异常,不影响核心用户数据写入:

String? firstToken;
try {
  firstToken = await FirebaseMessaging.instance.getToken();
} catch (e) {
  if (kDebugMode) {
    print('FCM Token获取失败: $e');
  }
}

// 写入时允许Token为null或空字符串
final userInformation = {
  // ...其他字段
  'token': firstToken ?? '',
};

5. 调用时机依赖页面,易被中断

checkUser()在HomeScreen的FutureBuilder中调用,若用户在Future完成前退出页面(如刚登录就返回),Future会被取消,写入流程中断。

修复:
将写入逻辑移至认证成功的回调中,确保认证完成后立即执行:

// 修改GoogleSignInProvider的googleLogin方法
Future googleLogin() async {
  try {
    // 原认证逻辑...

    await FirebaseAuth.instance.signInWithCredential(credential);
    
    // 认证成功后立即执行写入
    await checkUser();

    notifyListeners();
  } catch (e) {
    if (kDebugMode) {
      print(e.toString());
    }
  }
}

6. 文档ID设计不合理,存在并发风险

当前用自动生成的文档ID,需要通过where查询判断用户是否存在,效率低且可能出现同一用户多次登录时的并发写入问题。

修复:
用Firebase用户的uid作为文档ID,直接通过文档ID判断是否存在,避免并发问题:

Future<void> checkUser() async {
  try {
    final user = FirebaseAuth.instance.currentUser;
    if (user == null) return;

    final userDoc = FirebaseFirestore.instance.collection('users').doc(user.uid);
    final docSnapshot = await userDoc.get();

    if (!docSnapshot.exists) {
      String? firstToken;
      try {
        firstToken = await FirebaseMessaging.instance.getToken();
      } catch (e) {
        if (kDebugMode) print('FCM Token获取失败: $e');
      }

      final userInformation = {
        'id': user.uid,
        'name': user.displayName,
        'gmail': user.email?.toLowerCase(),
        'token': firstToken ?? ''
      };

      await userDoc.set(userInformation);
    } else {
      // 用户已存在时的更新逻辑,比如更新Token
      String? newToken;
      try {
        newToken = await FirebaseMessaging.instance.getToken();
      } catch (e) {
        if (kDebugMode) print('FCM Token获取失败: $e');
      }
      await userDoc.update({'token': newToken ?? ''});
    }
  } catch (e) {
    if (kDebugMode) {
      print('用户数据写入失败: $e');
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:44:54