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

MongoDB Realm Google Auth偶发base64/UTF-8登录错误解决方案

问题根因

两类报错的触发原因完全一致:你违反了AndroidX Activity Result API的使用规则,每次调用signInWithGoogle触发登录时,都会重复执行registerForActivityResult注册新的结果回调。
该API强制要求回调注册必须在Activity/Fragment的生命周期初始化阶段(Activity的onCreate、Fragment的onAttach/onCreate)完成,在生命周期走到STARTED状态之后重复注册,会导致回调关联的Intent引用指向被回收的内存地址,最终拿到的Google返回数据是脏数据:

  • 当脏数据刚好截断了ID Token字符串时,传给Realm的token不符合Base64编码规则,就会抛出illegal base64 data at input byte 345的认证错误
  • 当脏数据读到非UTF-8编码的内存垃圾字节(比如日志里的0xFF)时,Realm底层C++层做JSON序列化时会直接触发不可恢复的JNI崩溃,抛出invalid UTF-8 byte的错误
    你遇到的平均4次失败1次的概率,刚好和重复注册回调时旧回调残留、内存引用失效的概率吻合。
修复方案

按照Activity Result API的规范调整代码结构即可,核心改动三点:

  • 将ActivityResultLauncher、GoogleSignInClient的初始化和回调注册,移到Activity的onCreate生命周期中执行,全局只注册一次
  • 点击触发登录的方法中,仅调用launcher的launch方法拉起Google登录页,不再重复创建客户端、重复注册回调
  • 增加ID Token空值、格式校验的兜底逻辑,避免异常值传入Realm触发底层崩溃

修复后的参考代码:

// 声明为Activity成员变量
private ActivityResultLauncher<Intent> googleSignInLauncher;
private GoogleSignInClient googleSignInClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_auth);

    // 初始化Google登录客户端,仅执行一次
    GoogleSignInOptions gso = new GoogleSignInOptions
            .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken("MY-KEY.apps.googleusercontent.com")
            .build();
    googleSignInClient = GoogleSignIn.getClient(this, gso);

    // 注册登录结果回调,仅在onCreate中注册一次
    googleSignInLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                Task<GoogleSignInAccount> signInTask = GoogleSignIn.getSignedInAccountFromIntent(result.getData());
                handleSignInResult(signInTask);
            }
    );
}

// 登录按钮点击时调用该方法,仅负责拉起登录流程
private void signInWithGoogle() {
    Intent signInIntent = googleSignInClient.getSignInIntent();
    googleSignInLauncher.launch(signInIntent);
}

private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
    try {
        if (completedTask.isSuccessful()) {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            String token = account.getIdToken();
            // 兜底校验:token为空或格式不符合JWT规范直接返回,避免传入Realm触发异常
            if (token == null || token.split("\\.").length != 3) {
                Log.e("AUTH", "Google Auth failed: invalid empty or malformed id token");
                return;
            }
            Credentials googleCredentials =
                    Credentials.google(token, GoogleAuthType.ID_TOKEN);
            app.loginAsync(googleCredentials, it -> {
                if (it.isSuccess()) {
                    Log.v("AUTH",
                            "Successfully logged in to MongoDB Realm using Google OAuth.");
                } else {
                    Log.e("AUTH",
                            "Failed to log in to MongoDB Realm: ", it.getError());
                }
            });
        } else {
            Log.e("AUTH", "Google Auth failed: "
                    + completedTask.getException().toString());
        }
    } catch (ApiException e) {
        Log.w("AUTH", "Failed to log in with Google OAuth: " + e.getMessage());
    }
}

补充说明:调整后如果遇到极个别偶发的token无效问题,直接重试一次登录流程即可,不会再出现底层JNI崩溃的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 23:57:16