So I have been trying to solve this problem but I can't seem to know what's wrong. I have a button that when clicked calls PhoneAuthProvider which has 4 options: OnVerifiicationCompleted, OnVerificationFailed, OnCodeSent, and onCodeAutoRetrieval. The problem is that oncodesent is being called but the code that I put in there doesn't work, not even a debug log. All I get is an SMS message showing a verification code. And when I set a string value to onCodeSent's verificationID, the string is value: null. Here's my code:
sendLink.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popSound.start();
if (greenCheck.getVisibility() == View.VISIBLE) {
//send link
// we will finish this activity and send the link to the number
// an option to resend code to the number: it will be provided at the link
// in this format: resend code to (XXX)-XxX-XXXX
String number = phoneNumber.getText().toString();
phoneNumber.setText("");
sendLink.setEnabled(false);
PhoneAuthProvider.getInstance().verifyPhoneNumber(
number,
60,
TimeUnit.SECONDS,
MobileNumberActivity.this,
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
signInWithPhoneAuthCredential(phoneAuthCredential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
}
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
// verificationID never gets assigned s and it is null. log.d isn't on logcat
verificationID = s;
Log.d("testing", "onCodeSent: " + verificationID);
}
#Override
public void onCodeAutoRetrievalTimeOut(String s) {
super.onCodeAutoRetrievalTimeOut(s);
}
}
);
Intent i = new Intent(MobileNumberActivity.this, VerificationActivity.class);
startActivity(i);
finish();
} else if (phoneNumber.getText().toString().length() == 0) {
Toast.makeText(MobileNumberActivity.this, "Please enter a phone number", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MobileNumberActivity.this, "Please enter a valid phone number", Toast.LENGTH_SHORT).show();
}
}
});
Finally found the answer after trial and error. I don't know quite why this works but my guess is because since I am creating an instance of PhoneAuthProvider, it only works in oncreate. I had mine in oncreate but it was surrounded by a setOnClickListener as you see in the code above. So what worked for me is to start an intent to direct it to my verification activity, which in its oncreate method I created an instance of PhoneAuthProvider just by itself and it worked.
First activity:
sendLink.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popSound.start();
if (greenCheck.getVisibility() == View.VISIBLE) {
//send link
number = phoneNumber.getText().toString();
phoneNumber.setText("");
sendLink.setEnabled(false);
Intent i = new Intent(MobileNumberActivity.this, VerificationActivity.class);
startActivity(i);
finish();
} else if (phoneNumber.getText().toString().length() == 0) {
Toast.makeText(MobileNumberActivity.this, "Please enter a phone number", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MobileNumberActivity.this, "Please enter a valid phone number", Toast.LENGTH_SHORT).show();
}
}
});
Second activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verification);
mAuth = FirebaseAuth.getInstance();
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential credential) {
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verification without
// user action.
Log.d("COmpleted", "onVerificationCompleted:" + credential);
signInWithPhoneAuthCredential(credential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
Log.w("failed", "onVerificationFailed", e);
if (e instanceof FirebaseAuthInvalidCredentialsException) {
// Invalid request
// ...
} else if (e instanceof FirebaseTooManyRequestsException) {
// The SMS quota for the project has been exceeded
// ...
}
// Show a message and update the UI
// ...
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
Log.d("codesent", "onCodeSent:" + verificationId);
// Save verification ID and resending token so we can use them later
mVerificationID = verificationId;
mResendToken = token;
// ...
}
};
PhoneAuthProvider.getInstance().verifyPhoneNumber(
MobileNumberActivity.number, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mCallbacks);
}
Related
I am building an app that requires users to fill in the details for the sign-up screen.. once they fill in all the details and verification of details then I allow them to enter their email ID. once the email id is validated (1. blank email 2. invalid email id 3. existing email id check through Firebase) then the app will CREATE email for the user (using email password).. CREATION OF EMAIL has 3 phases.
A. Email creation itself and
B. Sending verification email to the user.
C. Waiting until the user verifies the email.
upon verification of email, I am allowing the user to enter the mobile number. On filling the mobile validation of it will happen (1. blank mobile 2. invalid mobile No 3. existing mobile check through Firebase). if validation turns positive I am asking them to verify the mobile through OTP (new activity). after OTP verification, Finally, I am storing all the user's data into firebase (except the password).
My actual problem lies here. I want users to log in through the phone OTP process or email password process. currently, I am unable to link the email and phone of the user as firebase is considering as 2 accounts. on google, I came to know that I had to link using the LinkWithCredential option. however, it's not working...
Here is my VerifyOTP codes where phone authentication happening...
public class VerifyOTP extends AppCompatActivity {
#BindView(R.id.PinViewUser)
PinView PinViewUser;
#BindView(R.id.btnVerify)
Button btnVerify;
#BindView(R.id.btnGetOTP)
Button btnGetOTP;
#BindView(R.id.btnResend)
Button btnResend;
#BindView(R.id.txtCodeVerificationText)
TextView txtCodeVerificationText;
#BindView(R.id.Verificationlabel)
TextView Verificationlabel;
#BindView(R.id.txtNoteToUser)
TextView txtNoteToUser;
FirebaseAuth mAuth;
AuthCredential emailCredential;
String UserPhoneNo, CodeBySystem, PhNoThroughSignUp, PhNoThroughForgotPassword, ForwardEmailToNextClass, GetCredEmail, GetCredPass;
PhoneAuthProvider.ForceResendingToken mResendToken;
private static final String TAG = "AnonymousAuth";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RunAppOnFullScreenMode();
setContentView(R.layout.activity_verify_o_t_p);
ButterKnife.bind(this);
//get Ph No & Other Details from SignupLayout
PhNoThroughSignUp = getIntent().getStringExtra(ReUsuableCode.CustomMobileNo);
GetCredEmail = getIntent().getStringExtra("CredEmail");
GetCredPass = getIntent().getStringExtra("CredPass");
emailCredential = EmailAuthProvider.getCredential(GetCredEmail, GetCredPass);
//get Ph No from ForgotPassword
PhNoThroughForgotPassword = getIntent().getStringExtra("FPMobile");
if (PhNoThroughSignUp == null) {
UserPhoneNo = PhNoThroughForgotPassword;
} else {
UserPhoneNo = PhNoThroughSignUp;
}
Toast.makeText(this, "Email: " + GetCredEmail + "Password: " + GetCredPass + "Phone: " + UserPhoneNo, Toast.LENGTH_LONG).show();// this is working
txtCodeVerificationText.setText("Click On Get OTP Button to Get the OTP on the Mentioned Phone No\n\n Note: Standard SMS charges May Apply");
Log.d(TAG, "DetailsCollected");
// Initialize Firebase Auth
mAuth = FirebaseAuth.getInstance();
//Send OTPCode to User
btnGetOTP.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SendVerificationCodeToUser(UserPhoneNo);
Log.d(TAG, "Verification Code Sent");
txtNoteToUser.setVisibility(View.VISIBLE);
txtCodeVerificationText.setText("Enter the One Time Password received on\n " + UserPhoneNo);
Toast.makeText(VerifyOTP.this, "OTP Initiated!! Wait For Auto Verification of OTP", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
btnVerify.setVisibility(View.VISIBLE);
}
}, 10000); // where 1000 is equal to 1 sec (1 * 1000)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
btnResend.setVisibility(View.VISIBLE);
}
}, 60000); // where 1000 is equal to 1 sec (1 * 1000)
}
});
//ReSend OTPCode to User
btnResend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
resendVerificationCode(UserPhoneNo, mResendToken);
txtCodeVerificationText.setText("Resent verification code to " + UserPhoneNo + "\n\n Note: Standard SMS charges May Apply");
btnResend.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
btnResend.setVisibility(View.VISIBLE);
}
}, 60000); // where 1000 is equal to 1 sec (1 * 1000)
}
});
//Manual Click on VerifyButton
btnVerify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String code = PinViewUser.getText().toString();
if (ReUsuableCode.fieldisEmpty(code)) {
PinViewUser.setError("Field is Empty");
} else {
VerifyCode(CodeBySystem, code);
}
}
});
}
//======================================= Other Private Codes==================
private void SendVerificationCodeToUser(String phNo) {
PhoneAuthOptions options =
PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(phNo) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(mCallbacks) // OnVerificationStateChangedCallbacks
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}
public void linkCredential(AuthCredential credential) {
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
Toast.makeText(VerifyOTP.this, "linkWithCredential:success", Toast.LENGTH_SHORT).show();
if (PhNoThroughSignUp == null) {
Intent GoToAnotherLayout1 = new Intent(VerifyOTP.this, SetPassword.class);
ForwardEmailToNextClass = getIntent().getStringExtra("FEmail");
GoToAnotherLayout1.putExtra("FEmail", ForwardEmailToNextClass);
startActivity(GoToAnotherLayout1);
finish();
} else {
Intent GoToAnotherLayout1 = new Intent(VerifyOTP.this, Retailer_SignUP.class);
GoToAnotherLayout1.putExtra(ReUsuableCode.MobileRegistration, "Mobile Validation Successful");
setResult(RESULT_OK, GoToAnotherLayout1);
finish();
}
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(VerifyOTP.this, "linkWithCredential:failure" + task.getException().toString(), Toast.LENGTH_SHORT).show();
}
}
});
}
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks =
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onCodeSent(#NonNull String s, #NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
// Save verification ID and resending token so we can use them later
CodeBySystem = s;
mResendToken = forceResendingToken;
Log.d(TAG, "OnCode Completed");
}
#Override
public void onVerificationCompleted(#NonNull PhoneAuthCredential phoneAuthCredential) {
Log.d(TAG, "On Verification start");
Toast.makeText(VerifyOTP.this, "OTP Verification Successful", Toast.LENGTH_SHORT).show();
String code = phoneAuthCredential.getSmsCode();
if (code != null) {
PinViewUser.setText(code);
VerifyCode(CodeBySystem, code);
Log.d(TAG, "Pre Link State");
linkCredential(emailCredential);
Log.d(TAG, "Post Link State");
}
}
#Override
public void onVerificationFailed(#NonNull FirebaseException e) {
Log.d(TAG, "Verification Failed");
if (e instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(VerifyOTP.this, "Failed to Verify!! Try After Some Time...", Toast.LENGTH_SHORT).show();
return;
} else if (e instanceof FirebaseTooManyRequestsException) {
Toast.makeText(VerifyOTP.this, "Too Many Attempts!! Try After Some Time...", Toast.LENGTH_SHORT).show();
return;
} else {
Toast.makeText(VerifyOTP.this, "Some Other Error Occured...", Toast.LENGTH_SHORT).show();
return;
}
}
};
private void VerifyCode(String verificationId, String code) {
PhoneAuthCredential Credential = PhoneAuthProvider.getCredential(verificationId, code);
Log.d(TAG, "Verified Code");
}
// [START resend_verification]
private void resendVerificationCode(String phoneNumber,
PhoneAuthProvider.ForceResendingToken token) {
PhoneAuthOptions options =
PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(mCallbacks) // OnVerificationStateChangedCallbacks
.setForceResendingToken(token) // ForceResendingToken from callbacks
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}
here are my error logs:
Please do guide me where I am missing. How to do I make a single account for the user?
I was able to get an answer to my code. Here is the website which I referred to fix the code: Learning Path for Linking Phone and Email
Steps to Link with 2nd Auth Provider of Firebase:
As per my scenario, I am first making the user enter an email ID and hence I make the user to first SIGN IN using email ID and password, which is nothing but,
Creation of Account with Email and Password
Sending Verification email (Optional step)
Waiting until User validates email ID (Optional Step)
Signing in the User using first Auth Provider (EmailAuthProvider).
After the signing process is complete. I made the user enter a mobile number so that he can proceed to validate the Ph No. In this follow the below process
Send a verification code to the user's phone
In the callbacks method of onVerificationCompleted. instead of regular signing-in with phAuth provider you have to use Linkwithcredentials(phcredentials)
which is:
a)
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
b)
linkCredential(PhCredential);
If you are using the manual verification of OTP then link the 2a and 2b step to verifybtn as well.
public void linkCredential(AuthCredential credential) {
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(VerifyOTP.this, "linkWithCredential:failure" + task.getException().toString(), Toast.LENGTH_SHORT).show();
}
}
});
i am looking for a way to find which code is sent to me from firebase phone authentication because i want to manually verify that code.Now the problem is firebase is autometically detecting the sms and onVerificationCompleted() is called but i have a button and i want to manually enter otp code and verify.Below is my code.Any help would be appreciated.Thanks
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phonenumber,
120,
TimeUnit.SECONDS,
this, new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(#NonNull PhoneAuthCredential phoneAuthCredential) {
Intent intent = new Intent(PhoneVerification.this, PictureActivity.class);
Log.e("iamhere","Credential IS"+phoneAuthCredential);
intent.putExtra("email",email);
intent.putExtra("phoneNumber",phonenumber);
intent.putExtra("password",password);
startActivity(intent);
Toast.makeText(PhoneVerification.this, "Please fill the registration form", Toast.LENGTH_LONG).show();
}
#Override
public void onVerificationFailed(#NonNull FirebaseException e) {
Toast.makeText(PhoneVerification.this, "Failed: "+e.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onCodeSent(#NonNull String s, #NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
Toast.makeText(PhoneVerification.this, "Check your phone for verification code", Toast.LENGTH_LONG).show();
String mVerificationId = s;
}
});
In case if code does not get detected automatically, the user has to manually enter it through EditText
loginBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String txt = otpEditText.getText().toString().trim();
if (txt.isEmpty() || txt.length() < 6) {
otp.setError("Enter valid code");
return;
}
//verifying the code entered manually
if (isOnline()) {
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, txt);
signInWithPhoneAuthCredential(credential);
} else {
showSnack(relativeLayout, "Unable to connect! Check internet connection");
}
}
});
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(Verification.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
//verification successfull do next task
} else {
//verification unsuccessful.. display an error message
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(Verification.this, "Incorrect OTP entered", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(Verification.this, "Unable to verify please retry later", Toast.LENGTH_LONG).show();
}
}
}
});
}
Here is the auto verification:
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
//Getting the code sent by SMS
String code = phoneAuthCredential.getSmsCode();
//sometime the code is not detected automatically
//in this case the code will be null
//so user has to manually enter the code
if (code != null) {
otpEditText.setText(code);
//verifying the code
verifyVerificationCode(code);
}
}
#Override
public void onVerificationFailed(FirebaseException e) {
FancyToast.makeText(Verification.this, e.getMessage(), FancyToast.LENGTH_LONG, FancyToast.CONFUSING, false).show();
}
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
//storing the verification id that is sent to the user
mVerificationId = s;
}
};
Check out the Firebase documentation for more info.
I am using firebase phone authentication for verifying phone number. But, there is an issue when I try to switch any other app or just press the home button in the middle of the process is going on, i.e in between the process has started and ended. Even if the OTP is correct and the time is not expired it always shows the FirebaseAuthInvalidCredentialsException with the following message.
The SMS code has expired. Please re-send the verification code to try again.
Previously, I found out that when the activity pause and resumes back in the middle of the process is going on, the authentication process (either verification of OTP or sending the OTP ) stops and it does not resume. So, for that, I manually started the process. Now, the process starts but it returns the above exception always.
By using the method resumeProcess() in on Resume. Now, receiveOTP() works fine. but veirifcation of OTP has still the issue. (as explined just above).
I am using a dialog for phone authentication.
The code I've written for phone authentication and for the issue is as follows.
To resume the process manually, which was stopped on pause. I am using resumeProcess() method in onResume().
In fragment's onResume()
#Override
public void onResume() {
super.onResume();
if (phoneAuthDialog != null && phoneAuthDialog.isShowing()) {
phoneAuthDialog.resumeProcess();
}
}
And, In dialog...
public void resumeProcess(){
if(isReceivingOtpSms){
receiveOtp(phoneNumber,null);
}
if(isVerifyingOtp){
verifyOtp();
}
}
for receiving 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);
}
The setPhoneVerificationCallback() method is used for handling verificationcallback.
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");
}
};
}
The verifyOTP() method
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));
}
}
The verifyCredentials method verifies the OTP is correct or not.
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));
}
}
}
});
}
}
Please help me with the issue and feel free to ask if my question is not clear. The major issue is
When even the OTP is correct and the time is not expired. It still shows the code has expired. and it happens only in the case when we pasue and resume back to the activity. in the middle of a process. (by in the middle of a process I mean, the verification process has started but before it completes its verification process (success or failure) I press switch to another app and come back to the app)
#Riddhi I think the problem is with the verificationId which you are sending at the time of verification. The Code seems to be good. I had the same problem previously when I am sending the verificationId.
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;
}
};
}
I hope it works for you. Could you get back to me after you check this code?
I want to add mobile number verification module in my application. I am using firebase for this and OTP is getting successfully sent to the particular mobile number but I want to validate whether the OTP entered is equal to the OTP sent to the respective mobile number.
I don't want to use the following code,
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(FirebasePhoneActivity.this, "Verification Success", Toast.LENGTH_SHORT).show();
} else {
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(FirebasePhoneActivity.this, "Verification Failed, Invalid credentials", Toast.LENGTH_SHORT).show();
}
}
}
});
break;
because using the above code lets the user Sign-In using mobile number. I want only to cross verify the OTP and don't want to Sign-In using MOBILE NUMBER.
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
codeSent = s;
resendToken = forceResendingToken;
}
Using the above code doesn't give the code that's sent but a random string value.
PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
codeReceivedByUser = phoneAuthCredential.getSmsCode();
}
The above code is getting called only when the OTP is received to his mobile and not in someone else's mobile(case when we give other person's mobile number)
Is there any way to validate the OTP when sent to someone else's mobile without using signInWithCredential method? Kindly help. Thanks in advance.
Try below code(call method one by one)
private void setListener() {
callbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
Toast.makeText(context, "Verification Completed" + phoneAuthCredential, Toast.LENGTH_SHORT).show();
}
#Override
public void onVerificationFailed(FirebaseException e) {
try {
ActivityHelper.dismissProgressDialog();
} catch (Throwable throwable) {
CustomLogHandler.printErrorlog(throwable);
}
if (e instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(context ,"Verification Failed" + e, Toast.LENGTH_SHORT).show();
} else if (e instanceof FirebaseTooManyRequestsException) {
Toast.makeText(context, "Verification Failed" + e, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Verification Failed" + e, Toast.LENGTH_SHORT).show();
}
isResendClicked = false;
}
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
try {
ActivityHelper.dismissProgressDialog();
} catch (Throwable throwable) {
CustomLogHandler.printErrorlog(throwable);
}
Toast.makeText(getActivity(), "Code sent to your registered device", Toast.LENGTH_SHORT).show();
isResendClicked = false;
verificationId = s;
resendtoken = forceResendingToken;
}
};
}
private void callGetOTPApi() {
try {
ActivityHelper.showProgressDialog(getActivity(), "Loading...", false);
PhoneAuthProvider.getInstance().verifyPhoneNumber(number, 60, TimeUnit.SECONDS, getActivity(), callbacks);
} catch (Throwable throwable) {
CustomLogHandler.printErrorlog(throwable);
}
}
I am new to Android development. I am not getting OTP message from Fire base but if I enter the code manually then it works. I am not sure why I am not getting text message. Your help is highly appreciated. I am not sure whether I am doing correctly sendVerificationcode method correctly or not.
Steps Completed:
1) I added GSON file to app directory
2) I added test phone number in the firebase console
3) I added SHA1 code to fire base
4) I added SMS permission in the Android manifest file.
5) I enabled firebase authentication in Android studio
6) I tried different phone numbers too
VerifyPhoneActivity.java
public class VerifyPhoneActivity extends AppCompatActivity {
private String verificationId;
private FirebaseAuth mAuth;
private ProgressBar progressBar;
private EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verify_phone);
mAuth = FirebaseAuth.getInstance();
progressBar = findViewById(R.id.progressbar);
editText = findViewById(R.id.editTextCode);
String phonenumber = getIntent().getStringExtra("phonenumber");
sendVerificationCode(phonenumber);
findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String code = editText.getText().toString().trim();
if (code.isEmpty() || code.length() < 6) {
editText.setError("Enter code...");
editText.requestFocus();
return;
}
verifyCode(code);
}
});
}
private void verifyCode(String code) {
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
signInWithCredential(credential);
}
private void signInWithCredential(PhoneAuthCredential credential) {
// private void signInWithCredential(PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Intent intent = new Intent(VerifyPhoneActivity.this, ProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} else {
Toast.makeText(VerifyPhoneActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
private void sendVerificationCode(String number) {
progressBar.setVisibility(View.VISIBLE);
PhoneAuthProvider.getInstance().verifyPhoneNumber(
number,
60,
TimeUnit.SECONDS,
TaskExecutors.MAIN_THREAD,
mCallBack
);
}
private PhoneAuthProvider.OnVerificationStateChangedCallbacks
mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
verificationId = s;
}
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
String code = phoneAuthCredential.getSmsCode();
if (code != null) {
editText.setText(code);
verifyCode(code);
}
System.out.println("Hello Phone Number"+code);
}
#Override
public void onVerificationFailed(FirebaseException e) {
Toast.makeText(VerifyPhoneActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
};
}
Below code looks like not working:
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
String code = phoneAuthCredential.getSmsCode();
// String code="000000";
if (code != null) {
editText.setText(code);
verifyCode(code);
}
System.out.println("Hello Phone Number2"+code);
}
Use like this following:
onCreate
mAuth = FirebaseAuth.getInstance();
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks()
{
#Override
public void onVerificationCompleted(PhoneAuthCredential credential)
{
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verificaiton without
// user action.
Log.d(TAG, "onVerificationCompleted:" + credential);
Log.e("number","credential=-=-=>>><<>>>signInWithPhoneAuthCredential-->>");
signInWithPhoneAuthCredential(credential);
}
#Override
public void onVerificationFailed(FirebaseException e)
{
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
Log.e(TAG, "onVerificationFailed", e);
// Show a message and update the UI
// ...
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token)
{
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
Log.e(TAG, "onCodeSent:" + verificationId+"<<token>>"+token);
// Save verification ID and resending token so we can use them later
mVerificationId = verificationId;
//mResendToken = token;
// ...
}
};
//String phoneNumber=Settings.PREFIX + Settings.PREFIX_PHONE;
String phoneNumber="your phone number with prefix";
Log.e("number","credential=-=-=>>>22222>>"+phoneNumber);
if(phoneNumber!=null && !phoneNumber.isEmpty())
{
startPhoneNumberVerification(phoneNumber);
}
Method:
private void startPhoneNumberVerification(String phoneNumber)
{
Log.e("startPhoneNumber","startPhoneNumberVerification------>>"+phoneNumber);
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mCallbacks); // OnVerificationStateChangedCallbacks
Log.e("startPhoneNumber","startPhoneNumberVerification--2222222---->>"+phoneNumber);
}
Method:
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.e(TAG, "signInWithCredential:success");
} else
{
// Sign in failed, display a message and update the UI
Log.e(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException)
{
}
}
}
});
}