Issue
I am using newest firebase sdk for auth but otp auto fill is not working. OTP SMS is successfully received, When I enter manually it is working without any issue. But I need to get that OTP automatically without user involvement.
My code:
mAuth = FirebaseAuth.getInstance();
editText = findViewById(R.id.sixdigit);
mTextViewCountDown = findViewById(R.id.text_view_countdown);
progress = new ProgressDialog(GVerifyotpActivity.this);
progress.setMessage("Waiting....");
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
String phonenumber = getIntent().getStringExtra("phonenumber");
sendVerificationCode(phonenumber);
findViewById(R.id.pnext).setOnClickListener(v -> {
String code = editText.getText().toString().trim();
if (code.isEmpty() || code.length() < 6) {
editText.setError("Enter code...");
editText.requestFocus();
return;
}
verifyCode(code);
});
mButtonStartPause = findViewById(R.id.button_start_pause);
mButtonStartPause.setOnClickListener(view -> {
resetTimer();
startTimer();
resendVerificationCode(phonenumber, mResendToken);
});
}
private void verifyCode(String code) {
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
signInWithCredential(credential);
if(progress!=null && !progress.isShowing()) {
progress.show();
}
}
private void signInWithCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
//Success!
}).addOnFailureListener(unused-> Toast.makeText(this, R.string.try_1, Toast.LENGTH_SHORT).show());
} else {
Toast.makeText(GVerifyotpActivity.this, Objects.requireNonNull(task.getException()).getMessage(), Toast.LENGTH_LONG).show();
}
});
}
private void sendVerificationCode(String number) {
PhoneAuthOptions options =
PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(number) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(mCallbacks) // OnVerificationStateChangedCallbacks
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}
private void startTimer() {
new CountDownTimer(mTimeLeftInMillis, 1000) {
@Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
@Override
public void onFinish() {
mButtonStartPause.setEnabled(true);
}
}.start();
}
private void resetTimer() {
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
mButtonStartPause.setEnabled(false);
}
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);
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
public void testPhoneAutoRetrieve() {
// [START auth_test_phone_auto]
// The test phone number and code should be whitelisted in the console.
String phoneNumber = "+9471268xxxxx";
String smsCode = "123456";
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
FirebaseAuthSettings firebaseAuthSettings = firebaseAuth.getFirebaseAuthSettings();
// Configure faking the auto-retrieval with the whitelisted numbers.
firebaseAuthSettings.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode);
PhoneAuthOptions options = PhoneAuthOptions.newBuilder(firebaseAuth)
.setPhoneNumber(phoneNumber)
.setTimeout(120L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(PhoneAuthCredential credential) {
// Instant verification is applied and a credential is directly returned.
// ...
Log.d("TAGRR", "onVerificationCompleted: "+credential);
}
// [START_EXCLUDE]
@Override
public void onVerificationFailed(FirebaseException e) {
Log.d("TAGRR", "onVerificationFailed: "+e);
}
// [END_EXCLUDE]
})
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
// [END auth_test_phone_auto]
}
private PhoneAuthProvider.OnVerificationStateChangedCallbacks
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
verificationId = s;
mResendToken = forceResendingToken;
}
@Override
public void onVerificationCompleted(@NonNull 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("TAGP", "onVerificationCompleted:" + credential);
String code = credential.getSmsCode();
if (code != null) {
editText.setText(code);
}
signInWithCredential(credential);
if(progress!=null && !progress.isShowing()) {
progress.show();
}
}
@Override
public void onVerificationFailed(FirebaseException e) {
Toast.makeText(GVerifyotpActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
};
Dependencies
implementation 'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.1'
implementation 'com.google.android.gms:play-services-auth:19.2.0'
Android DeviceCheck API is added successfully, SHA-256 keys are inserted in Firebase settings! SafetyNet is activated!
classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.google.gms:google-services:4.3.8'
Everything has done according to the Firebase documentation [https://firebase.google.com/docs/auth/android/phone-auth]
I tested with testPhoneAutoRetrieve() method, It works but with a real sim it's not working! Credentials are not taking from the received sms!
Logs found
Ignoring header X-Firebase-Locale because its value was null.
FirebaseAuth: [SmsRetrieverHelper] Timed out waiting for SMS.
PhoneAuthProvider: Sms auto retrieval timed-out.
Is there anything I have forgot? Is there any problem with app name character limits or something? example app name- MyApp: Abc, Xyz (Country)
- List item
Solution
I faced the same issue and mine was due to the app name too long to contain the hashcode. Below are few work around:
- You need to make sure the message you receive contains the hash of your app. Below is the right format :
123456 is your verification code for %APP_NAME%.
abc_hascode_xyz
If your SMS does not contain the hashCode at the end, you might have to shorten your app name to not more than 15 characters.
If your app is already published on Google Play, the name in the SMS will be the same as the one in the Google play store.
If you changed the name to 15 characters and the error still persists, you might have to wait for at least 24hours for the change to reflect on firebase.
if after all the above it's still not resolved, please check if your receiver is well configured in the code.
check out the new GooglePlay policy on app names: Examples of common app names violations
Answered By - Gomez NL
Answer Checked By - Pedro (JavaFixing Volunteer)