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

Android端Firebase OTP验证失效问题求助

解决Firebase OTP登录无法验证的问题

看起来你的OTP验证流程有几个关键问题,导致无法完成验证,我来帮你一步步排查和修复:

核心问题分析

  • 1. LoginActivity中Intent初始化错误&重复启动实例
    你在LoginActivity的onCreate里直接写了final String otp = intent.getStringExtra("otp");,但根本没初始化intent变量,第一次启动LoginActivity时会直接抛出空指针异常。另外,从Otp页面用startActivity跳回LoginActivity会创建一个全新的LoginActivity实例,原来的实例里保存的mVerificationId会丢失,导致无法验证OTP。

  • 2. 未正确处理OTP回传后的验证逻辑
    你拿到OTP后没有结合之前Firebase返回的mVerificationId创建PhoneAuthCredential,也没有调用登录验证方法,自然无法完成验证。

  • 3. 重复定义方法&变量混淆
    在mCallbacks的onVerificationCompleted里你定义了一个内部的signInWithPhoneAuthCredential方法,直接调用System.exit(0),这会直接退出应用,而不是调用外部的真正处理登录的方法。另外你同时定义了verificationId和mVerificationId两个变量,容易混淆。

修复步骤&修改后的代码

第一步:修改LoginActivity,用startActivityForResult启动Otp页面,并在onActivityResult接收OTP

修改后的LoginActivity代码:

public class LoginActivity extends AppCompatActivity {
    EditText phonetextview;
    String phone_number;
    FirebaseAuth mAuth;
    private PhoneAuthProvider.ForceResendingToken mResendToken;
    private String mVerificationId; // 统一用这个变量保存verificationId
    PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;
    private static final String TAG = "LoginActivity";
    private static final int OTP_REQUEST_CODE = 100; // 请求码,用于识别返回结果

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        mAuth = FirebaseAuth.getInstance();

        mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            @Override
            public void onVerificationCompleted(PhoneAuthCredential credential) {
                // 自动验证成功的情况,直接调用登录方法
                Toast.makeText(getBaseContext(), "自动验证成功", Toast.LENGTH_SHORT).show();
                signInWithPhoneAuthCredential(credential);
            }

            @Override
            public void onVerificationFailed(FirebaseException e) {
                e.printStackTrace();
                Toast.makeText(getApplicationContext(), "验证失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) {
                Log.d(TAG, "onCodeSent:" + verificationId);
                mVerificationId = verificationId;
                mResendToken = token;
                // 用startActivityForResult启动Otp页面,以便接收返回的OTP
                Intent i = new Intent(getApplicationContext(), Otp.class);
                startActivityForResult(i, OTP_REQUEST_CODE);
            }
        };

        CardView card_view = findViewById(R.id.cardView);
        card_view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                phonetextview = findViewById(R.id.phonetextview);
                phone_number = phonetextview.getText().toString().trim();
                // 注意:PhoneNumberUtils.formatNumber可能会改变号码格式,建议直接拼接国家码,确保号码正确
                sendVerificationCode("+91" + phone_number);
                Toast.makeText(getApplicationContext(), "发送验证码到:" + "+91" + phone_number, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void sendVerificationCode(String phoneNumber) {
        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                phoneNumber,        // Phone number to verify
                60,                 // Timeout duration
                TimeUnit.SECONDS,   // Unit of timeout
                this,               // Activity (for callback binding)
                mCallbacks);        // Callbacks
    }

    // 接收Otp页面返回的结果
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == OTP_REQUEST_CODE && resultCode == RESULT_OK) {
            if (data != null) {
                String otp = data.getStringExtra("otp");
                if (otp != null && mVerificationId != null) {
                    // 创建验证凭证
                    PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, otp);
                    // 调用登录方法
                    signInWithPhoneAuthCredential(credential);
                }
            }
        }
    }

    private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            // 登录成功,这里可以跳转到主页面
                            Log.d(TAG, "signInWithCredential:success");
                            Toast.makeText(getBaseContext(), "登录成功!", Toast.LENGTH_SHORT).show();
                            FirebaseUser user = task.getResult().getUser();
                            // 比如:Intent mainIntent = new Intent(LoginActivity.this, MainActivity.class);
                            // startActivity(mainIntent);
                            // finish();
                        } else {
                            // 登录失败
                            Log.w(TAG, "signInWithCredential:failure", task.getException());
                            String errorMsg = "登录失败";
                            if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                                errorMsg = "验证码无效,请重新输入";
                            }
                            Toast.makeText(getBaseContext(), errorMsg, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }
}

第二步:修改Otp页面,用setResult返回OTP,而不是重新启动LoginActivity

修改后的Otp代码:

public class Otp extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_otp);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                EditText et1 = findViewById(R.id.et1);
                EditText et2 = findViewById(R.id.et2);
                EditText et3 = findViewById(R.id.et3);
                EditText et4 = findViewById(R.id.et4);
                EditText et5 = findViewById(R.id.et5);
                EditText et6 = findViewById(R.id.et6);

                // 拼接OTP
                String otp = et1.getText().toString().trim() +
                        et2.getText().toString().trim() +
                        et3.getText().toString().trim() +
                        et4.getText().toString().trim() +
                        et5.getText().toString().trim() +
                        et6.getText().toString().trim();

                // 检查OTP长度是否符合要求(一般是6位)
                if (otp.length() != 6) {
                    Toast.makeText(Otp.this, "请输入完整的6位验证码", Toast.LENGTH_SHORT).show();
                    return;
                }

                // 将OTP返回给LoginActivity
                Intent intent = new Intent();
                intent.putExtra("otp", otp);
                setResult(RESULT_OK, intent);
                finish(); // 关闭当前页面,回到原来的LoginActivity
            }
        });
    }
}

额外注意事项

  • 确保你已经在Firebase控制台正确配置了Android应用,并且添加了google-services.json文件。
  • 测试时使用真实的手机号(Firebase的OTP测试可以用控制台提供的测试号码,但正式环境需要真实号码)。
  • 处理号码格式:确保输入的手机号没有多余的空格或符号,国家码拼接正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:26:22