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

Android Firebase注册功能OTP验证失败问题求助

问题:OTP验证失效,Firebase发送正常但验证失败

问题详情

  • 开发场景:学校小组项目的注册页面,使用Firebase Auth实现手机号OTP验证
  • 异常现象:Firebase能正常发送OTP,但手动输入OTP后验证操作失败;移除OTP功能后,Realtime Database插入用户信息、Storage创建用户文件夹的功能完全正常
  • 已排查操作:重建项目、检查依赖配置、使用配对真机运行、添加AppCheck,问题仍未解决

问题根源分析

查看代码后发现核心问题:从RegistrationActivity跳转到PhoneVerificationActivity时,未传递sourceActivity参数,导致PhoneVerificationActivity验证成功后无法触发返回RegistrationActivity的逻辑,最终RegistrationActivity收到RESULT_CANCELED,判定验证失败。

具体逻辑矛盾点:

  • RegistrationActivity的initiatePhoneVerification()方法中,仅传递了phoneNumber参数,未添加sourceActivity的Extra标识
  • PhoneVerificationActivity的signInWithPhoneAuthCredential()方法中,需要判断sourceActivity是否为"RegistrationActivity"才会返回RESULT_OK,否则不会执行该分支逻辑

修复步骤

1. 修改RegistrationActivity的跳转逻辑

在initiatePhoneVerification()方法中添加sourceActivity参数:

private void initiatePhoneVerification() {
    String phoneNumber = phoneNumberEditText.getText().toString();
    Intent intent = new Intent(this, PhoneVerificationActivity.class);
    intent.putExtra("phoneNumber", phoneNumber);
    // 添加来源页面标识,让验证页面知道当前是注册流程
    intent.putExtra("sourceActivity", "RegistrationActivity");
    startActivityForResult(intent, PHONE_VERIFICATION_REQUEST);
}

2. 补充潜在检查点

  • 确认Firebase控制台中Phone Auth已启用,并且添加了正确的SHA-1/SHA-256指纹(调试和发布版本都需要配置)
  • 检查PhoneVerificationActivity布局文件中,OTP输入框的ID是否与代码中的editTextCode一致
  • 验证手机号格式:RegistrationActivity中处理后的手机号(如+63开头)需和Firebase发送验证码的手机号完全一致,避免格式不匹配导致验证失败

相关源码

RegistrationActivity 源码

package com.example.best_csportal;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;

public class RegistrationActivity extends AppCompatActivity {

    private static final int PHONE_VERIFICATION_REQUEST = 101;

    private EditText usernameEditText;
    private EditText phoneNumberEditText;
    private EditText passwordEditText;
    private EditText confirmPasswordEditText;
    private Button registerButton;
    private Button loginButton;
    private DatabaseReference databaseReference;
    private FirebaseAuth auth;

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

        // Initialize Firebase Auth
        auth = FirebaseAuth.getInstance();

        FirebaseDatabase database = FirebaseDatabase.getInstance("https://best-cs-default-rtdb.asia-southeast1.firebasedatabase.app");
        databaseReference = database.getReference("users");

        usernameEditText = findViewById(R.id.etext_rusername);
        phoneNumberEditText = findViewById(R.id.etext_rphone);
        passwordEditText = findViewById(R.id.etext_rpassword);
        confirmPasswordEditText = findViewById(R.id.etext_rcpassword);
        registerButton = findViewById(R.id.button_rregister);
        loginButton = findViewById(R.id.button_rlogin);

        registerButton.setOnClickListener(v -> initiatePhoneVerification());
        loginButton.setOnClickListener(v -> startActivity(new Intent(this, LoginActivity.class)));
    }

    private void initiatePhoneVerification() {
        String phoneNumber = phoneNumberEditText.getText().toString();
        Intent intent = new Intent(this, PhoneVerificationActivity.class);
        intent.putExtra("phoneNumber", phoneNumber);
        startActivityForResult(intent, PHONE_VERIFICATION_REQUEST);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PHONE_VERIFICATION_REQUEST && resultCode == RESULT_OK) {
            registerUser();
        } else {
            Toast.makeText(this, "OTP verification failed. Please try again.", Toast.LENGTH_LONG).show();
        }
    }

    private void registerUser() {
        String username = usernameEditText.getText().toString().trim();
        String rawPhoneNumber = phoneNumberEditText.getText().toString().trim();
        String password = passwordEditText.getText().toString().trim();
        String confirmPassword = confirmPasswordEditText.getText().toString().trim();

        // Process the phone number for the desired format
        final String phoneNumber;
        if (rawPhoneNumber.startsWith("0")) {
            phoneNumber = rawPhoneNumber.replaceFirst("0", "+63");
        } else if (!rawPhoneNumber.startsWith("+63")) {
            phoneNumber = "+63" + rawPhoneNumber;
        } else {
            phoneNumber = rawPhoneNumber;
        }

        if (username.isEmpty() || phoneNumber.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) {
            Toast.makeText(this, "All fields must be filled", Toast.LENGTH_SHORT).show();
            return;
        }

        if (!password.equals(confirmPassword)) {
            Toast.makeText(this, "Passwords do not match", Toast.LENGTH_SHORT).show();
            return;
        }

        // Check for duplicate usernames
        databaseReference.orderByChild("username").equalTo(username).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    Toast.makeText(RegistrationActivity.this, "Username already exists", Toast.LENGTH_SHORT).show();
                } else {
                    // Check for duplicate phone numbers
                    databaseReference.orderByChild("phoneNumber").equalTo(phoneNumber).addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot phoneSnapshot) {
                            if (phoneSnapshot.exists()) {
                                Toast.makeText(RegistrationActivity.this, "Phone number already used", Toast.LENGTH_SHORT).show();
                            } else {
                                // Register user in the Realtime Database
                                String userId = databaseReference.push().getKey();
                                String folderPath = "users/" + userId + "/";
                                User user = new User(username, phoneNumber, password, folderPath);
                                databaseReference.child(userId).setValue(user)
                                        .addOnCompleteListener(dbTask -> {
                                            if (dbTask.isSuccessful()) {
                                                createUserFolder(userId);
                                                Toast.makeText(RegistrationActivity.this, "Registration Successful", Toast.LENGTH_SHORT).show();
                                            } else {
                                                Toast.makeText(RegistrationActivity.this, "Registration Failed: " + dbTask.getException().getMessage(), Toast.LENGTH_SHORT).show();
                                            }
                                        });
                            }
                        }

                        @Override
                        public void onCancelled(DatabaseError databaseError) {
                            Toast.makeText(RegistrationActivity.this, "Error: " + databaseError.getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Toast.makeText(RegistrationActivity.this, "Error: " + databaseError.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void createUserFolder(String userId) {
        FirebaseStorage storage = FirebaseStorage.getInstance();
        StorageReference storageRef = storage.getReference();
        StorageReference userFolder = storageRef.child("users/" + userId + "/");

        // Create a dummy file to initialize the folder
        StorageReference dummyFile = userFolder.child("dummy.txt");
        byte[] data = "This is a placeholder to create the folder".getBytes();
        dummyFile.putBytes(data).addOnSuccessListener(aVoid -> {
            // Successfully created folder, now update the database
            databaseReference.child(userId).child("storagePath").setValue(userFolder.getPath())
                    .addOnFailureListener(e -> Toast.makeText(RegistrationActivity.this, "Failed to save storage path: " + e.getMessage(), Toast.LENGTH_SHORT).show());
        }).addOnFailureListener(exception -> {
            // Handle unsuccessful uploads
            Toast.makeText(RegistrationActivity.this, "Failed to create user folder: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
        });
    }
}

PhoneVerificationActivity 源码

package com.example.best_csportal;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
import java.util.concurrent.TimeUnit;
import com.google.firebase.FirebaseException;
import android.util.Log;
import android.app.Activity;

public class PhoneVerificationActivity extends AppCompatActivity {

    private EditText editTextCode;
    private Button buttonVerify;
    private FirebaseAuth mAuth;
    private String phoneNumber;
    private String verificationId;

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

        mAuth = FirebaseAuth.getInstance();
        editTextCode = findViewById(R.id.editTextCode);
        buttonVerify = findViewById(R.id.buttonVerify);

        // Retrieve the phone number passed from LoginActivity
        phoneNumber = getIntent().getStringExtra("phoneNumber");

        sendVerificationCodeToUser(phoneNumber);

        buttonVerify.setOnClickListener(v -> {
            String code = editTextCode.getText().toString().trim();
            if (!code.isEmpty()) {
                verifyVerificationCode(code);
            }
        });
    }

    private void sendVerificationCodeToUser(String phoneNumber) {
        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                phoneNumber,        // Phone number to verify
                60,                 // Timeout duration
                TimeUnit.SECONDS,   // Unit of timeout
                this,               // Activity (for callback binding)
                new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                    @Override
                    public void onVerificationCompleted(PhoneAuthCredential credential) {
                        // Auto-verification logic here
                        signInWithPhoneAuthCredential(credential);
                    }

                    @Override
                    public void onVerificationFailed(FirebaseException e) {
                        Log.e("PhoneVerification", "Verification failed: " + e.getMessage());
                        Toast.makeText(PhoneVerificationActivity.this, "Verification failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) {
                        Log.d("PhoneVerification", "Code sent successfully");
                        PhoneVerificationActivity.this.verificationId = verificationId; // Save the verification ID for later use
                    }
                }
        );
    }

    private void verifyVerificationCode(String code) {
        PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
        signInWithPhoneAuthCredential(credential);
    }

    private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, task -> {
                    if (task.isSuccessful()) {
                        String sourceActivity = getIntent().getStringExtra("sourceActivity");
                        if ("RegistrationActivity".equals(sourceActivity)) {
                            Intent resultIntent = new Intent();
                            setResult(Activity.RESULT_OK, resultIntent);
                            finish();
                        } else if ("LoginActivity".equals(sourceActivity)) {
                            Intent intent = new Intent(PhoneVerificationActivity.this, UserMainActivity.class);
                            startActivity(intent);
                            finish();
                        }
                    } else {
                        Toast.makeText(PhoneVerificationActivity.this, "Verification failed: " + task.getException().getMessage(), Toast.LENGTH_LONG).show();
                        setResult(Activity.RESULT_CANCELED);
                        finish();
                    }
                });
    }
}

内容的提问来源于stack exchange,提问作者Dingrat Kahlil John Roderick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:35:07