Firebase谷歌登录getCurrentUser.getEmail()返回null如何解决
Firebase谷歌登录
getCurrentUser().getEmail()返回null修复方案 问题表现
- 谷歌登录流程无报错,
getDisplayName()、用户UID等字段可正常读取,唯独getEmail()返回null - 本地已按照示例配置
requestEmail()权限,功能此前运行正常
核心原因
- 账号权限限制:个人用户在新版谷歌登录授权弹窗可主动选择不向应用提供邮箱;如果是企业谷歌Workspace账号,管理员可在后台统一限制第三方应用读取员工邮箱,这类场景下即使本地配置了邮箱请求权限,也无法获取到邮箱字段。
- 缓存数据异常:如果对应谷歌账号此前已经登录过应用,后续调整登录权限配置后,Firebase不会自动刷新已存在用户的字段缓存,会出现邮箱字段缺失的问题。
- 取值逻辑缺陷:仅从Firebase同步后的
FirebaseUser对象取邮箱,没有从谷歌登录原生返回的GoogleSignInAccount对象取值做兜底,Firebase同步链路异常时就会拿到null。
修复步骤
1. 增加邮箱取值兜底逻辑
不要只依赖FirebaseUser返回的邮箱,在谷歌登录回调拿到原生GoogleSignInAccount对象时就直接读取邮箱,传到后续认证逻辑里做兜底。
首先修改onActivityResult的登录结果处理逻辑:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "----------------------------onActivityResult---------------------------"); super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); try { GoogleSignInAccount account = task.getResult(ApiException.class); Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId()); // 直接从谷歌原生登录结果取邮箱作为兜底值 String fallbackEmail = account.getEmail(); firebaseAuthWithGoogle(account.getIdToken(), fallbackEmail); } catch (ApiException e) { Log.w(TAG, "Google sign in failed", e); } } }
对应调整firebaseAuthWithGoogle方法,优先用原生返回的邮箱,同时加空指针防护:
private void firebaseAuthWithGoogle(String idToken, String fallbackEmail) { Log.d(TAG, "------------------------firebaseAuthWithGoogle-----------------------"); AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null); mAuth.signInWithCredential(credential) .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { Log.d(TAG, "signInWithCredential:success"); FirebaseUser user = mAuth.getCurrentUser(); // 优先取Firebase返回的邮箱,为空时用谷歌原生结果的兜底值 String gmail_user_email = user.getEmail() != null ? user.getEmail() : fallbackEmail; Log.d(TAG, "gmail_user_email"+gmail_user_email); String gmail_user_name = user.getDisplayName(); Log.d(TAG, "gmail_user_name"+gmail_user_name); String gmail_user_phone = user.getPhoneNumber(); Log.d(TAG, "gmail_user_phone"+gmail_user_phone); String gmail_user_id = user.getUid(); Log.d(TAG, "gmail_user_id"+gmail_user_id); // 极端场景兜底:如果两个渠道都拿不到邮箱,引导用户重新授权 if (gmail_user_email == null) { new Display_Snackbar(UserLogin.this).Show_snack_bar("无法获取账号邮箱,请重新登录或更换账号尝试"); mAuth.signOut(); mGoogleSignInClient.signOut(); return; } new Display_Snackbar(UserLogin.this).Show_snack_bar("Sign in as "+gmail_user_email); int checkUser = user_tbl.CheckUser(gmail_user_email); if(checkUser>0) { Log.d(TAG, "user id exist in sqlite"); user_tbl.InsertLoginDetails(gmail_user_email,"1"); syncData(gmail_user_email); getDevices(gmail_user_email); }else{ Log.d(TAG, "user id not exist in sqlite"); InsertNewUser(gmail_user_email,"",gmail_user_name,""); } } else { Log.w(TAG, "signInWithCredential:failure", task.getException()); new Display_Snackbar(UserLogin.this).Show_snack_bar("Gmail Sign in failed"); } } }); }
2. 清理异常缓存
如果是已经登录过的老账号出现问题,直接在Firebase控制台的Authentication用户列表中删除对应用户,让用户重新走完整授权流程,即可拉取到完整的账号字段。
测试阶段可以在退出登录时同步清理谷歌登录缓存,避免旧授权缓存影响:
public void logout() { mAuth.signOut(); mGoogleSignInClient.signOut(); // 跳转回登录页 }
3. 核对授权配置
确认Google Cloud控制台的OAuth同意屏幕中,已经添加了邮箱读取权限;如果应用还处于测试阶段,要把测试用的谷歌账号加到测试白名单中,避免权限限制返回不全字段。
注意:不要把邮箱作为用户的唯一主键,Firebase返回的UID才是跨登录方式、跨设备稳定的用户唯一标识,即使用户后续修改谷歌账号绑定的邮箱,UID也不会变化,用UID做用户关联可以避免很多数据不一致问题。
内容的提问来源于stack exchange,提问作者Linet M Shaji
相关产品推荐
相关产品推荐

