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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:48:29