Flutter中Apple登录无法获取用户名问题求助
问题:Apple登录无法获取用户名(首次/再次登录均失败)
使用sign_in_with_apple: ^5.0.0和firebase_auth: ^4.12.1实现Apple登录注册,但无论首次注册还是再次登录,都无法从Apple登录获取用户名。尝试通过代码处理用户名更新,但始终无法拿到正确的用户名,求排查代码问题或告知首次注册时获取用户名的正确方式。
实现代码:
Future signInWithApple() async { _hasError = false; notifyListeners(); bool canAppleSignIn = await SignInWithApple.isAvailable(); if (canAppleSignIn == true) { // executing our authentication try { final credential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], ); final oauthCredential = OAuthProvider("apple.com").credential( idToken: credential.identityToken, ); final UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); if (userCredential.user?.displayName == null || (userCredential.user?.displayName != null && userCredential.user!.displayName!.isEmpty)) { final fixDisplayNameFromApple = [ credential.givenName ?? '', credential.familyName ?? '', ].join(' ').trim(); await userCredential.user?.updateDisplayName(fixDisplayNameFromApple); } if (userCredential.user?.email == null || (userCredential.user?.email != null && userCredential.user!.email!.isEmpty)) { await userCredential.user?.updateEmail(credential.email ?? ''); } user = FireStoreUser( email: userCredential.user?.email, imageUrl: userCredential.user?.photoURL ?? "https://winaero.com/blog/wp-content/uploads/2017/12/User-icon-256-blue.png", name: userCredential.user?.displayName, provider: "APPLE", uid: userCredential.user!.uid, ); await saveDataToSharedPreferences(); notifyListeners(); } on FirebaseAuthException catch (e) { switch (e.code) { case "account-exists-with-different-credential": _errorCode = "You already have an account with us. Use correct provider"; _hasError = true; notifyListeners(); break; case "null": _errorCode = "Some unexpected error while trying to sign in"; _hasError = true; notifyListeners(); break; default: _errorCode = e.toString(); _hasError = true; notifyListeners(); } } } else { _hasError = true; notifyListeners(); } }
解决方案
核心原因:Apple授权规则限制
Apple 仅在用户首次授权应用时,才会返回givenName、familyName和email;后续用户再次登录时,Apple不会再返回这些敏感信息,只会返回用户标识。你的代码未考虑该规则,同时存在Firebase用户实例未刷新的问题。
代码问题排查与修复
- Firebase用户实例未自动刷新:调用
updateDisplayName后,userCredential.user对象不会实时更新,直接读取会拿到旧值。 - 未持久化用户名:首次获取到用户名后未存入自有数据库(如Firestore),导致后续登录无数据可读取。
修改后的代码:
Future signInWithApple() async { _hasError = false; notifyListeners(); bool canAppleSignIn = await SignInWithApple.isAvailable(); if (canAppleSignIn) { try { final credential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], ); final oauthCredential = OAuthProvider("apple.com").credential( idToken: credential.identityToken, ); final UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); final firebaseUser = userCredential.user; String? displayName; // 1. 优先从Apple返回值获取(仅首次登录有效) if (credential.givenName != null || credential.familyName != null) { displayName = [credential.givenName ?? '', credential.familyName ?? ''].join(' ').trim(); if (firebaseUser != null && displayName.isNotEmpty) { await firebaseUser.updateDisplayName(displayName); // 手动刷新用户实例,获取最新displayName await firebaseUser.reload(); final updatedUser = FirebaseAuth.instance.currentUser; displayName = updatedUser?.displayName; } } else { // 2. Apple未返回时,读取Firebase已存的displayName displayName = firebaseUser?.displayName; // 3. 若Firebase也无数据,从自有数据库读取之前保存的用户名 // final firestoreDoc = await FirebaseFirestore.instance.collection('users').doc(firebaseUser?.uid).get(); // displayName = firestoreDoc.data()?['name']; } // 邮箱更新逻辑(同样仅首次登录能获取Apple返回的email) if (firebaseUser != null && credential.email != null && (firebaseUser.email == null || firebaseUser.email!.isEmpty)) { await firebaseUser.updateEmail(credential.email!); await firebaseUser.reload(); } // 使用处理后的displayName创建用户对象 user = FireStoreUser( email: FirebaseAuth.instance.currentUser?.email, imageUrl: FirebaseAuth.instance.currentUser?.photoURL ?? "https://winaero.com/blog/wp-content/uploads/2017/12/User-icon-256-blue.png", name: displayName, provider: "APPLE", uid: firebaseUser!.uid, ); // 首次登录时,将用户名持久化到自有数据库 if (credential.givenName != null && firebaseUser != null) { await FirebaseFirestore.instance.collection('users').doc(firebaseUser.uid).set({ 'name': displayName, 'email': FirebaseAuth.instance.currentUser?.email, 'uid': firebaseUser.uid, 'provider': "APPLE" }, SetOptions(merge: true)); } await saveDataToSharedPreferences(); notifyListeners(); } on FirebaseAuthException catch (e) { switch (e.code) { case "account-exists-with-different-credential": _errorCode = "你已有账户,请使用对应登录方式"; break; case "null": _errorCode = "登录时发生未知错误"; break; default: _errorCode = e.toString(); } _hasError = true; notifyListeners(); } } else { _hasError = true; notifyListeners(); } }
关键注意事项
- 首次授权必须持久化信息:拿到Apple返回的用户名和邮箱后,务必存入自有数据库,后续登录Apple不会再返回这些数据。
- Firebase用户需手动刷新:调用
updateDisplayName或updateEmail后,必须调用reload()并重新获取currentUser,才能拿到最新值。 - 后续登录的降级逻辑:如果Apple未返回用户名,优先读取Firebase的
displayName,再从自有数据库读取,避免出现空值。
内容的提问来源于stack exchange,提问作者Ahsan
相关产品推荐
相关产品推荐

