Flutter+Firebase集成Apple Sign In时DisplayName无法更新至用户记录
解决Flutter Firebase Apple Sign In无法更新DisplayName的问题
问题原因分析
- Apple授权限制:Apple仅在用户首次授权登录时返回
fullName信息,后续登录不会再返回该字段。如果是重复登录,你的fixDisplayNameFromApple会是空字符串,导致更新无效。 - Web端逻辑缺失:当前代码仅处理了移动端的DisplayName更新,Web端通过
signInWithPopup获取的用户信息没有做同步处理。 - 异步操作未确认:
updateDisplayName是异步操作,虽调用了reload,但未确保操作完成后再执行后续逻辑,也没有错误捕获,无法排查更新是否失败。
修复后的代码
import 'dart:convert'; import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'auth_util.dart'; /// 生成加密安全的随机nonce,用于凭证请求 String generateNonce([int length = 32]) { final charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; final random = Random.secure(); return List.generate(length, (_) => charset[random.nextInt(charset.length)]) .join(); } /// 返回输入字符串的sha256哈希值(十六进制格式) String sha256ofString(String input) { final bytes = utf8.encode(input); final digest = sha256.convert(bytes); return digest.toString(); } Future<UserCredential> appleSignIn() async { if (kIsWeb) { final provider = OAuthProvider("apple.com") ..addScope('email') ..addScope('fullName'); final userCredential = await FirebaseAuth.instance.signInWithPopup(provider); final firebaseUser = userCredential.user; final additionalInfo = userCredential.additionalUserInfo; // Web端从additionalUserInfo中获取用户姓名 if (firebaseUser != null && firebaseUser.displayName == null && additionalInfo?.profile != null) { final givenName = additionalInfo!.profile!['given_name'] ?? ''; final familyName = additionalInfo.profile!['family_name'] ?? ''; final displayName = '$givenName $familyName'.trim(); if (displayName.isNotEmpty) { try { await firebaseUser.updateDisplayName(displayName); await firebaseUser.reload(); } catch (e) { debugPrint('更新Web端DisplayName失败: $e'); } } } return userCredential; } // 移动端逻辑 final rawNonce = generateNonce(); final nonce = sha256ofString(rawNonce); final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], nonce: nonce, ); final oauthCredential = OAuthProvider("apple.com").credential( idToken: appleCredential.identityToken, rawNonce: rawNonce, ); final fixDisplayNameFromApple = [ appleCredential.givenName ?? '', appleCredential.familyName ?? '', ].join(' ').trim(); print(fixDisplayNameFromApple); final userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); final firebaseUser = userCredential.user; // 仅当用户displayName为空且获取到有效姓名时才更新 if (firebaseUser != null && firebaseUser.displayName == null && fixDisplayNameFromApple.isNotEmpty) { try { await firebaseUser.updateDisplayName(fixDisplayNameFromApple); await firebaseUser.reload(); // 重新获取用户对象确保本地数据更新 final updatedUser = FirebaseAuth.instance.currentUser; print('更新后的DisplayName: ${updatedUser?.displayName}'); } catch (e) { debugPrint('更新移动端DisplayName失败: $e'); } } return userCredential; } Future<User?> signInWithApple(BuildContext context) => signInOrCreateAccount(context, appleSignIn, 'APPLE');
关键修复点
- 增加错误捕获:用
try-catch包裹updateDisplayName操作,方便排查更新失败原因。 - Web端逻辑补全:从
additionalUserInfo.profile中提取姓名并更新,和移动端保持一致逻辑。 - 条件校验增强:只有当
fixDisplayNameFromApple不为空时才执行更新,避免空字符串覆盖。 - 强制刷新用户数据:更新后重新获取
currentUser,确保本地缓存的用户信息是最新的。
额外注意事项
- 测试时请确保是首次授权Apple登录,后续登录Apple不会返回姓名信息,若要重新测试,需在Apple设置中取消对该应用的授权。
- 如果需要在用户后续登录时更新姓名,需引导用户在应用内手动修改并调用
updateDisplayName。
内容的提问来源于stack exchange,提问作者Daryl
相关产品推荐
相关产品推荐

