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

安卓应用Firebase手机认证重装后跳转异常问题求助

问题:Firebase手机号认证卸载重装后跳过登录选择界面直接进入OTP验证

我在安卓应用中实现了Firebase Mobile Authentication,添加了用户未登出时的自动登录功能。但卸载并重新安装应用后,应用没有进入可选择手机号登录或跳过登录的LoginLayout界面,而是直接跳转到需输入手机号获取OTP验证的界面。

以下是我的SplashScreen.java代码:

package com.example.androidbarberbooking;

import static android.content.ContentValues.TAG;

import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.Manifest;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import com.example.androidbarberbooking.Common.Common;
import com.example.androidbarberbooking.Model.UserInfoModel;
import com.example.androidbarberbooking.Utils.UserUtils;
import com.firebase.ui.auth.AuthMethodPickerLayout;
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.textfield.TextInputEditText;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.installations.FirebaseInstallations;
import com.google.firebase.messaging.FirebaseMessaging;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Completable;


public class SplashScreen extends AppCompatActivity{

    private final static int LOGIN_REQUEST_CODE = 7171;
    private List<AuthUI.IdpConfig> providers;
    private FirebaseAuth firebaseAuth;
    private FirebaseAuth.AuthStateListener listener;

    FirebaseFirestore database;
    CollectionReference userInfoRef;

    @BindView(R.id.progress_bar)
    ProgressBar progress_bar;


    public void onStart() {
        super.onStart();
        delaySplashScreen();
    }

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

        init();

    }

    private void init() {

        ButterKnife.bind(this);

        database = FirebaseFirestore.getInstance();
//        userInfoRef = database.getReference(Common.USER_INFO_REFERENCE);
        userInfoRef = database.collection("User");


        providers = Arrays.asList(
                new AuthUI.IdpConfig.PhoneBuilder().build()
//                new AuthUI.IdpConfig.GoogleBuilder().build()
                );

        firebaseAuth = FirebaseAuth.getInstance();
        listener = myFirebaseAuth -> {
            FirebaseUser user = myFirebaseAuth.getCurrentUser();
            if (user == null)
            {
                showLoginLayout();
            }
            else{
                //getting token for notification
                FirebaseMessaging.getInstance().getToken()
                        .addOnCompleteListener(new OnCompleteListener<String>() {
                            @Override
                            public void onComplete(@NonNull Task<String> task) {
                                Common.updateToken(getBaseContext(),task.getResult());
                                String taskID = task.getResult();
                                Log.d(TAG, "FCM registration token: " + taskID);
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(SplashScreen.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                            }
                        });

                //Update Token
                FirebaseInstallations.getInstance()
                        .getToken(true)
                        .addOnFailureListener(e-> Toast.makeText(SplashScreen.this, e.getMessage(), Toast.LENGTH_SHORT).show())
                        .addOnSuccessListener(installationTokenResult -> {
                            Log.d("TOKEN", installationTokenResult.getToken());
                            UserUtils.updateToken(SplashScreen.this, installationTokenResult.getToken());
                        });

                //checkUserFromFirebase();
                DocumentReference presentUser = userInfoRef.document(user.getPhoneNumber().toString());
                presentUser.get()
                        .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                            @Override
                            public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                if (task.isSuccessful())
                                {
                                    DocumentSnapshot userSnapshot = task.getResult();
                                    if (!userSnapshot.exists())
                                    {
                                        showRegisterLayout(user.getPhoneNumber().toString());
                                    }
                                    else {
                                        Common.currentUser = userSnapshot.toObject(UserInfoModel.class);
                                        goToHomeActivity(Common.currentUser);
                                    }
                                }
                            }
                        });
            }
        };
    }

    private void goToHomeActivity(UserInfoModel userInfoModel) {
        Common.currentUser = userInfoModel;//Init Value
        startActivity(new Intent(SplashScreen.this, HomeActivity.class));
        finish();
    }

    private void showRegisterLayout(String edtPnNum) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.DialogTheme);
        View itemView = LayoutInflater.from(this).inflate(R.layout.layout_register, null);

        TextInputEditText edtFsName = (TextInputEditText) itemView.findViewById(R.id.edtFsName);
        TextInputEditText edtLsName = (TextInputEditText) itemView.findViewById(R.id.edtLsName);
        TextInputEditText edtPhnNum = (TextInputEditText) itemView.findViewById(R.id.edtPnNum);
        TextInputEditText edtmail = (TextInputEditText) itemView.findViewById(R.id.edtmail);

        ImageView btn_continue = (ImageView) itemView.findViewById(R.id.btn_register);

        //setData
        if(FirebaseAuth.getInstance().getCurrentUser().getPhoneNumber() != null &&
                !TextUtils.isEmpty(FirebaseAuth.getInstance().getCurrentUser().getPhoneNumber())) {
            edtPhnNum.setText(FirebaseAuth.getInstance().getCurrentUser().getPhoneNumber());
        }

        //setView
        builder.setView(itemView);
        AlertDialog dialog = builder.create();
        dialog.show();

        btn_continue.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TextUtils.isEmpty(edtFsName.getText().toString()))
                {
                    Toast.makeText(SplashScreen.this, "Please Enter Your First Name", Toast.LENGTH_SHORT).show();
                }
                else if (TextUtils.isEmpty(edtLsName.getText().toString()))
                {
                    Toast.makeText(SplashScreen.this, "Please Enter Your Last Name", Toast.LENGTH_SHORT).show();
                }
                else if (TextUtils.isEmpty(edtPhnNum.getText().toString()))
                {
                    Toast.makeText(SplashScreen.this, "Please Enter Your Phone Number", Toast.LENGTH_SHORT).show();
                }
                else if (TextUtils.isEmpty(edtmail.getText().toString()))
                {
                    Toast.makeText(SplashScreen.this, "Please Enter Your Email", Toast.LENGTH_SHORT).show();
                }
                else {
                    UserInfoModel userInfoModel = new UserInfoModel();
                    userInfoModel.setFirstName(edtFsName.getText().toString());
                    userInfoModel.setLastName(edtLsName.getText().toString());
                    userInfoModel.setPhoneNumber(edtPhnNum.getText().toString());
                    userInfoModel.setEmail(edtmail.getText().toString());

                    userInfoRef.document(edtPnNum)
                            .set(userInfoModel)
                            .addOnSuccessListener(new OnSuccessListener<Void>() {
                                @Override
                                public void onSuccess(Void unused) {
                                    Toast.makeText(SplashScreen.this, "Registration Successful!!", Toast.LENGTH_SHORT).show();
                                    dialog.dismiss();
                                    goToHomeActivity(userInfoModel);
                                }
                            })
                            .addOnFailureListener(new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception e) {
                                    Toast.makeText(SplashScreen.this, "" + e.getMessage(), Toast.LENGTH_SHORT).show();
                                }
                            });
                }
            }
        });

    }

    private void showLoginLayout() {
        AuthMethodPickerLayout authMethodPickerLayout = new AuthMethodPickerLayout
                .Builder(R.layout.layout_sign_in)
                .setPhoneButtonId(R.id.phoneSignIn)
                .build();

        startActivityForResult(AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setAuthMethodPickerLayout(authMethodPickerLayout)
                .setIsSmartLockEnabled(false)
                .setTheme(R.style.LoginTheme)
                .setAvailableProviders(providers)
                .build(), LOGIN_REQUEST_CODE);
    }

    private void delaySplashScreen() {
        progress_bar.setVisibility(View.VISIBLE);

        Completable.timer(3, TimeUnit.SECONDS,
                AndroidSchedulers.mainThread())
                .subscribe(() ->
                        firebaseAuth.addAuthStateListener(listener));
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == LOGIN_REQUEST_CODE)
        {
            IdpResponse response = IdpResponse.fromResultIntent(data);
            if (resultCode == RESULT_OK)
            {
                FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
            }
            else
            {
                Toast.makeText(this, "[ERROR]: " + response.getError().getMessage(), Toast.LENGTH_SHORT).show();
            }
        }
    }
}

问题原因

Firebase Auth的AuthUI默认会保留设备上的登录相关缓存(部分安卓系统卸载重装后仍可能保留账号凭据),加上当前逻辑仅在FirebaseUser为null时显示LoginLayout,导致卸载重装后Firebase直接尝试恢复之前的手机号登录会话,跳过了自定义的登录选择界面。

修复方案

1. 彻底禁用Firebase Auth的凭据恢复

修改showLoginLayout()方法,完善setIsSmartLockEnabled参数,彻底禁止凭据保存与恢复:

private void showLoginLayout() {
    AuthMethodPickerLayout authMethodPickerLayout = new AuthMethodPickerLayout
            .Builder(R.layout.layout_sign_in)
            .setPhoneButtonId(R.id.phoneSignIn)
            .build();

    startActivityForResult(AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAuthMethodPickerLayout(authMethodPickerLayout)
            // 第一个参数禁用SmartLock自动登录,第二个参数禁用凭据保存
            .setIsSmartLockEnabled(false, false)
            .setTheme(R.style.LoginTheme)
            .setAvailableProviders(providers)
            .build(), LOGIN_REQUEST_CODE);
}

2. 标记重装状态,强制显示登录选择界面

通过SharedPreferences记录应用是否为卸载重装后的首次启动,确保此时必现登录选择界面:

// 在init()方法中修改listener逻辑
listener = myFirebaseAuth -> {
    SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
    boolean isReinstall = prefs.getBoolean("isReinstall", true);
    
    if (isReinstall) {
        showLoginLayout();
        // 标记为已初始化,下次启动不再触发
        prefs.edit().putBoolean("isReinstall", false).apply();
    } else {
        FirebaseUser user = myFirebaseAuth.getCurrentUser();
        if (user == null) {
            showLoginLayout();
        } else {
            // 原有自动登录逻辑(保持不变)
            FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(new OnCompleteListener<String>() {
                    @Override
                    public void onComplete(@NonNull Task<String> task) {
                        Common.updateToken(getBaseContext(),task.getResult());
                        String taskID = task.getResult();
                        Log.d(TAG, "FCM registration token: " + taskID);
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Toast.makeText(SplashScreen.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });

            FirebaseInstallations.getInstance()
                    .getToken(true)
                    .addOnFailureListener(e-> Toast.makeText(SplashScreen.this, e.getMessage(), Toast.LENGTH_SHORT).show())
                    .addOnSuccessListener(installationTokenResult -> {
                        Log.d("TOKEN", installationTokenResult.getToken());
                        UserUtils.updateToken(SplashScreen.this, installationTokenResult.getToken());
                    });

            DocumentReference presentUser = userInfoRef.document(user.getPhoneNumber().toString());
            presentUser.get()
                    .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                        @Override
                        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                            if (task.isSuccessful())
                            {
                                DocumentSnapshot userSnapshot = task.getResult();
                                if (!userSnapshot.exists())
                                {
                                    showRegisterLayout(user.getPhoneNumber().toString());
                                }
                                else {
                                    Common.currentUser = userSnapshot.toObject(UserInfoModel.class);
                                    goToHomeActivity(Common.currentUser);
                                }
                            }
                        }
                    });
        }
    }
};

3. 添加跳过登录功能

在自定义的layout_sign_in布局中添加“跳过登录”按钮,处理点击事件直接进入首页:

// 在showLoginLayout()对应的界面中添加(若使用自定义布局,需在布局文件中先添加按钮)
Button btnSkip = findViewById(R.id.btn_skip_login);
btnSkip.setOnClickListener(v -> {
    // 标记为游客模式,直接进入首页
    Common.currentUser = null;
    startActivity(new Intent(SplashScreen.this, HomeActivity.class));
    finish();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:02:59