【问题标题】:Firebase phone authentication shows exception when activity resumes: "The sms code has expired. Please re-send the verification code to try again."活动恢复时 Firebase 电话身份验证显示异常:“短信代码已过期。请重新发送验证码以重试。”
【发布时间】:2019-07-14 22:56:29
【问题描述】:

我正在使用 Firebase 电话身份验证来验证电话号码。但是,当我尝试切换任何其他应用程序或只是按下主页按钮时会出现问题,该过程正在进行中,即在该过程开始和结束之间。即使OTP 正确且时间未过期,它始终显示 FirebaseAuthInvalidCredentialsException 和以下消息。

短信代码已过期。请重新发送验证码重试。

以前,我发现当活动暂停并在进程中间恢复时,身份验证过程(验证 OTP 或发送 OTP )停止并且不会恢复。因此,为此,我手动启动了该过程。现在,该过程开始了,但它总是返回上述异常。

通过在简历中使用resumeProcess() 方法。现在,receiveOTP() 工作正常。但是OTP的验证仍然存在问题。 (如上文所述)。

我正在使用对话框进行电话身份验证。

我为电话验证和问题编写的代码如下。

手动恢复进程,该进程在暂停时停止。我在onResume() 中使用resumeProcess() 方法。

在片段的onResume()

@Override
public void onResume() {
    super.onResume();
    if (phoneAuthDialog != null && phoneAuthDialog.isShowing()) {
        phoneAuthDialog.resumeProcess();
    }
}

而且,在对话框中...

public void resumeProcess(){
    if(isReceivingOtpSms){
        receiveOtp(phoneNumber,null);
    }

    if(isVerifyingOtp){
        verifyOtp();
    }
}

用于接收 OTP。

private void receiveOtp(String phoneNumber,PhoneAuthProvider.ForceResendingToken forceResendingToken) {
    if (connectionDetector != null && connectionDetector.isConnectingToInternet()) {

        setPhoneVerificationCallback();
        isReceivingOtpSms =true;
        showProgress();

        //for receiving otp for the first time
        if(forceResendingToken==null){
            PhoneAuthProvider.getInstance().verifyPhoneNumber(
                    phoneNumber,        // Phone number to verify
                    60,                 // Timeout duration
                    TimeUnit.SECONDS,   // Unit of timeout
                    activity,               // Activity (for callback binding)
                    mCallbacks);        // OnVerificationStateChangedCallbacks
        }

        //for resending otp
        else {
            PhoneAuthProvider.getInstance().verifyPhoneNumber(
                    phoneNumber,        // Phone number to verify
                    60,                 // Timeout duration
                    TimeUnit.SECONDS,   // Unit of timeout
                    activity,               // Activity (for callback binding)
                    mCallbacks,          // OnVerificationStateChangedCallbacks
                    forceResendingToken);
        }

    } else
        showToast(activity, Constants.MESSAGE_NO_CONNECTION);
}

setPhoneVerificationCallback() 方法用于处理验证回调。

private void setPhoneVerificationCallback() {
    mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        @Override
        public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
            hideProgress();               //to hide progressbar.
            isReceivingOtpSms=false;
            //some ui process....
            verifyCredentials(phoneAuthCredential); 
        }

        @Override
        public void onCodeAutoRetrievalTimeOut(String s) {
            super.onCodeAutoRetrievalTimeOut(s);
        }

        @Override
        public void onVerificationFailed(FirebaseException e) {
            e.printStackTrace();
            hideProgress();
            isReceivingOtpSms=false;

            if (e instanceof FirebaseNetworkException) {
                showToast(activity, activity.getString(R.string.err_noconnection_message));
            } else if (e instanceof FirebaseAuthInvalidCredentialsException) {
                e.printStackTrace();
                showToast(activity, "Incorrect phone number format. Check your mobile number and country code twice.");
            } else {
                showToast(activity, e.getMessage());
            }
        }

        @Override
        public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
            super.onCodeSent(verificationId, forceResendingToken);
            hideProgress();
            isReceivingOtpSms=false;
            PhoneAuthDialogRefactored.this.verificationId = verificationId;
            PhoneAuthDialogRefactored.this.forceResendingToken = forceResendingToken;

            //some ui process ...

            showToast(activity, "code sent to your number");
        }
    };
}

verifyOTP() 方法

private void verifyOtp() {
    String otp = etOtp.getText().toString().trim();
    if (otp.length() == 6) {

        if (connectionDetector != null && connectionDetector.isConnectingToInternet()) {
            if (verificationId != null) {
                Log.e("Verification ID : ", verificationId);
                PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, otp.trim());
                verifyCredentials(credential);
            } else {
                showToast(activity, "Please wait for a while! the code is not sent yet.");
            }
        } else {
            showToast(activity, activity.getString(R.string.err_noconnection_message));
        }
    } else {
        errOtp.setVisibility(View.VISIBLE);
        errOtp.setText(activity.getString(R.string.err_required));
    }
}

verifyCredentials 方法验证 OTP 是否正确。

private void verifyCredentials(PhoneAuthCredential credential) {
    isVerifyingOtp=true;
    showProgress();

    if (activity != null) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(activity, task -> {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        hideProgress();
                        isVerifyingOtp=false;
                        //some ui process...

                    } else {
                        // Sign in failed, display a message and update the UI
                        hideProgress();
                        isVerifyingOtp=false;
                        Log.w("Phone authentication", "signInWithCredential:failure", task.getException());
                        if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                            // The verification code entered was invalid

                            Exception exception=task.getException();
                            if(exception.getMessage().equals("The sms code has expired. Please re-send the verification code to try again.")){
                                showToast(activity,exception.getMessage());
                                errOtp.setVisibility(View.VISIBLE);
                                errOtp.setText(activity.getString(R.string.err_expired_code));
                            }
                            else {
                                errOtp.setVisibility(View.VISIBLE);
                                errOtp.setText(activity.getString(R.string.err_wrong_otp));
                            }
                        }
                    }
                });
    }
}

请帮助我解决这个问题,如果我的问题不清楚,请随时提出。主要问题是

即使 OTP 正确且时间未过期。它仍然显示代码已过期。并且仅在我们暂停并恢复活动时才会发生。在一个过程的中间。 (我的意思是在一个过程的中间,验证过程已经开始,但在它完成验证过程(成功或失败)之前,我按下切换到另一个应用程序并返回应用程序)

【问题讨论】:

  • 如果您继续进行相同的活动并输入代码会怎样?
  • @RahulKhurana 它运行良好。在这种情况下。只有当我们最小化应用程序或按下主页按钮或类似情况时才会出现问题。
  • 只需检查 mCallbacks 以查看它是否为空。如果它不为空,则不要重置它
  • @RahulKhurana 没用。
  • 你能把你的完整代码贴在这里吗?

标签: android firebase firebase-authentication


【解决方案1】:

@Riddhi 我认为问题出在您在验证时发送的 verifyId 上。代码似乎很好。我之前在发送验证 ID 时遇到了同样的问题。

public class OtpVerificationActivity extends AppCompatActivity implements View.OnClickListener {

    EditText mobileNumber,otpText;
    Button sendOtp,verifyOtp;
    FirebaseAuth mAuth;
    String codeSent;

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

        mobileNumber = findViewById(R.id.mobileNumber);
        otpText = findViewById(R.id.otpText);
        sendOtp = findViewById(R.id.sendOtp);
        verifyOtp = findViewById(R.id.verifyOtp);

        sendOtp.setOnClickListener(this);
        verifyOtp.setOnClickListener(this);

        mAuth = FirebaseAuth.getInstance();

    }

    @Override
    public void onClick(View v) {

        switch (v.getId()){

            case R.id.sendOtp:

                sendVerificationCode();
                break;

            case R.id.verifyOtp:

                verifyCodeSent();
                break;
        }

    }

    private void verifyCodeSent() {

        String code = otpText.getText().toString();
        PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeSent,code);
        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()) {
                            // Sign in success, update UI with the signed-in user's information
                            Log.d("verifyCode", "signInWithCredential:success");

                            Toast.makeText(OtpVerificationActivity.this, "Successful", Toast.LENGTH_SHORT).show();
                            //FirebaseUser user = task.getResult().getUser();
                            // ...
                        } else {
                            // Sign in failed, display a message and update the UI
                            Log.w("verifyCode", "signInWithCredential:failure", task.getException());
                            if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                                // The verification code entered was invalid
                                Toast.makeText(OtpVerificationActivity.this, ""+task.getException().getMessage(), Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                });
    }

    private void sendVerificationCode() {

        String phoneNumber = mobileNumber.getText().toString();

        if (phoneNumber.isEmpty()){
            mobileNumber.setError("mobile number cannot be empty");
            mobileNumber.requestFocus();
        }

        if (phoneNumber.length() < 10){
            mobileNumber.setError("Please enter a valid phone");
            mobileNumber.requestFocus();
        }

        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                "+91" + phoneNumber,        // Phone number to verify (I hardcoded it only for Indian Mobile numbers).
                60,                 // Timeout duration
                TimeUnit.SECONDS,   // Unit of timeout
                this,               // Activity (for callback binding)
                mCallbacks);
    }

    PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        @Override
        public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {

        }

        @Override
        public void onVerificationFailed(FirebaseException e) {

        }

        @Override
        public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
            super.onCodeSent(s, forceResendingToken);

            codeSent = s;
        }
    };
}

我希望它对你有用。你检查完这段代码后能回复我吗?

【讨论】:

  • 感谢您帮助我。但verificationId 只是您在codesent 方法中使用的变量s 的另一个名称。而且您还使用了我正在使用的相同代码。正如我在问题中所说,在正常情况下它工作正常
猜你喜欢
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
  • 2019-08-23
  • 2020-07-20
  • 2019-01-13
  • 1970-01-01
  • 2020-07-22
  • 1970-01-01
相关资源
最近更新 更多