安卓应用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
相关产品推荐
相关产品推荐

