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