恢复活动后,Firebase电话身份验证会显示异常:“短信代码已过期。请重新发送验证码,然后重试。”

时间:2019-02-21 05:51:40

标签: android firebase firebase-authentication

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

  

SMS代码已过期。请重新发送验证码,然后重试。

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

通过使用“继续”中的方法resumeProcess()。现在,receiveOTP()工作正常。但OTP的自动化仍然是问题。 (如上图所示)。

我正在使用一个对话框进行电话验证。

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

要手动恢复该过程,该过程已暂停。我正在resumeProcess()中使用onResume()方法。

在片段的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正确且时间未到期。它仍然显示代码已过期。而且只有在我们继续进行并恢复活动时才会发生。在过程的中间。 (我的意思是说,在过程的中间,验证过程已经开始,但是在完成验证过程(成功或失败)之前,我按下了切换到另一个应用程序,然后返回到该应用程序)

1 个答案:

答案 0 :(得分:1)

@Riddhi我认为问题出在验证时您要发送的VerificationId。该守则似乎很好。发送验证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;
        }
    };
}

我希望它对您有用。检查此代码后,您可以再找我吗?