I'm trying to set up OTP verification so when the user enters their phone number, I send them a pin code, the onCodeSent() is called and I receive the code pin, but the problem is when onVerificationCompleted() is called, I would like to move to another activity where the user can enter the code pin to verify but it is not called at all and I don't understand why. Any help would be appreciated guys, thank you.
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(p0: PhoneAuthCredential) {
// here i want to get the smscode and send it over the next activity to verify
// but this method is not called at all
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("code",p0.smsCode)
startActivity(this)
}
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(code: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(code, p1)
}
override fun onCodeAutoRetrievalTimeOut(p0: String) {
super.onCodeAutoRetrievalTimeOut(p0)
}
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
onVerificationCompleted() will only be called when the phone number has been verified without any input from the user. To do what you are trying, you should be sending your intent inside onCodeSent() instead.
Here is a rough flow of events (that are covered in detail in the documentation):
Obtain phone number from user
Call PhoneAuthProvider.verifyPhoneNumber(auth) (as you are already) to send the pin to the user
onCodeSent() is called, with the verification ID and a resending token.
Inside of onCodeSent(), create an intent to launch the "pin input screen" with the verification ID.
Get a pin from the user and then combine it with the verification ID by calling PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, userInput)
Use that credential to sign in the user using signInWithCredential(credential).
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// if here, phone number was verified automatically
mAuth.signInWithCredential(credential)
.addOnCompleteListener(/* ... */)
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(verificationId: String, resendToken: PhoneAuthProvider.ForceResendingToken) {
// if here, code was sent to phone number
// open pin input screen
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("verificationId",verificationId)
startActivity(this)
}
}
// we aren't using onCodeAutoRetrievalTimeOut, so it's omitted.
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
I was also facing this problem but when I added my project to google cloud console, enable api services(google cloud console) and enable phone verification(google cloud console)
then onVerificationCompleted is working fine.
https://console.cloud.google.com/home
Related
hi guys i'm trying to do auto login in my app but before login done i wonder if the user verified his email or no.
the problem : even if i verified my account the code doesn't see this and said false.
and here is my code.
class SignInActivity : BaseActivity<SignInViewModel, ActivitySignInBinding>(), Navigator {
private lateinit var preferenceManger: PreferenceManger
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
preferenceManger = PreferenceManger(applicationContext)
autoLogin()
binding.vm = viewModel
viewModel.navigator = this
addPrefManger()
}
private fun autoLogin() {
DataUtils.firebaseUser = Firebase.auth.currentUser
if (preferenceManger.getBoolean(Constants.KEY_IS_SIGNED_IN)) {
when {
DataUtils.firebaseUser!!.isEmailVerified -> {
startActivity(Intent(this, HomeActivity::class.java))
finish()
}
else -> {
startActivity(Intent(this, VerificationActivity::class.java))
finish()
}
}
}
}
this line is always false even if i verified my account.
DataUtils.firebaseUser!!.isEmailVerified
While the verification status of the user profile is updated on the server as soon as they've clicked the link, it may take up to an hour before that information is synchronized to the Android app.
If you want to detect the email verification in the app before it is automatically synchronized, you can:
Sign the user out and in again.
Force reloading of the user profile (after the user has clicked the link) by calling reload on the user object. You can put a button in your UI to do this, or automatically call that, for example in the onResume of the activity.
Also see:
How to verify email without the need of signing in again while using FirebaseUI-auth?
Verification email activity not refreshing
in my application first i authenticate user email and then i am verifying user email i have set dialog activity to inform user to check email and verify email i have close button in dialog activity if user click on it dialog will be dismissed
i have implemented override fun onResume() method first activity and in this method i check user have verified email or not by auth.getInstance().currentUser.isEmailVerified
i ran this app i got email and successfully verify but in onResume() method auth.getInstance().currentUser.isEmailVerified returns false
auth.createUserWithEmailAndPassword(binding.email.text.toString(),binding.password.text.toString()).addOnCompleteListener { task->
Log.d("userAuthenticated","yes")
if(task.isSuccessful)
{
val currUser=auth.currentUser
Log.d("TaskIsSuccessful","Yes")
currUser!!.sendEmailVerification().addOnSuccessListener {
Log.d("Emailissent","yes")
uniqueFirebaseAuthId=task.result!!.user!!.uid.toString()
val sentEmailbinding=ActivityEmailVarificationSignUpBinding.inflate(layoutInflater)
val dialog = Dialog(this#SignUp)
dialog.setContentView(sentEmailbinding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.setCancelable(false)
sentEmailbinding.closebtn.setOnClickListener{
dialog.dismiss()
Log.d("Iamback","Yes")
}
dialog.show()
Log.d("verified",currUser.isEmailVerified.toString())
Log.d("Dialogshown","yes")
Log.d("uniqueFirebaseAuthValue","${uniqueFirebaseAuthId} ")
}.addOnFailureListener {
Log.d("emailauthverification",it.toString())
}
}
task.addOnFailureListener {
Log.d("TaskFail",it.toString())
}
onResume() function
override fun onResume() {
super.onResume()
val userEnterdName=binding.uiqueusername.toString()
val currUser=FirebaseAuth.getInstance().currentUser
if(currUser!!.isEmailVerified) {
val verifiedUser=UseratFirebase(userEnterdName,binding.email.toString(),binding.password.toString())
val uniqueAuthId=uniqueFirebaseAuthId.toString()
database.reference.child("users").child(uniqueAuthId).setValue(verifiedUser).addOnSuccessListener {
val intent=Intent(this#SignUp,SignIn::class.java)
intent.putExtra("Email",binding.email.text.toString())
intent.putExtra("password",binding.email.toString())
}.addOnFailureListener {
Toast.makeText(this#SignUp,"Error occured while stroting data",Toast.LENGTH_LONG).show()
}
}
else
{
Log.d("Curruser", "${currUser.toString() } -> ${currUser.isEmailVerified}")
Toast.makeText(this#SignUp,"Please verify Your Account",Toast.LENGTH_LONG).show()
}
}
Verifying the user's email address happens in another application (you click the link in your mail app, and then it verifies that action in the browser), so you app is not aware of it right away.
The information is encoded in the user's ID token, which is refreshed automatically every hour, or when the user signs in again. So you can either wait/force the user to sign in again, or you can tell the SDK to refresh the token by calling user.getIdToken(true) or user.reload().
I implemented Facebook Login functionality in my android app. But there is a unwanted behaviour that appears.
loginButton.registerCallback(callbackManager,
object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
Log.d("mytag", "onSuccess: ${result?.accessToken?.userId}")
}
override fun onCancel() {
}
override fun onError(error: FacebookException?) {
}
})
So when onSuccess is called, everything is okay, i get the userId. But internally this saves some user authentication data inside SharedPreferences. Which is not what i want, my intention is to get only userId and send it to my server and that is it. (I mean it is not actually my aim to use facebook login for app, i just want to get userProfile image and send it to server).
How can i achieve this result?
Firebase Phone Authentication sent otp automatically not fill in edittext. otp is manually entered in edittext. how do automatically detect the incoming verification SMS and perform verification with user action?
Otp.kt
private fun sendVerificationCode(phone : String){
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(phone) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks(){
override fun onVerificationCompleted(p0: PhoneAuthCredential) {
binding.btnOtpVerify.visible(true)
binding.progressbarVerify.visible(false)
val code = p0.smsCode
if(code != null){
binding.etOtpView.setText(code)
VerifyVerificationCode(code)
signInWithPhoneAuthCredential(p0)
}
}
override fun onVerificationFailed(p0: FirebaseException) {
binding.btnOtpVerify.visible(true)
binding.progressbarVerify.visible(false)
Toast.makeText(this#OtpVerification,p0.message,Toast.LENGTH_LONG).show()
}
override fun onCodeSent(p0: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(p0, p1)
binding.btnOtpVerify.visible(true)
binding.progressbarVerify.visible(false)
storedVerificationID = p0
resendingToken = p1
}
}
Make sure you have enabled SafetyNet thing this on google.
For the autofill editText work with the code inside the function onVerificationCompleted
As I understand it, you are using Firebase PhoneAuth to verify the phone number and send an OTP via the Firebase server, and you need a workflow to detect the incoming SMS containing the OTP and auto-fill your EditText with this OTP.
To enable automatic OTP detection, you can use the SmsRetriever API and the related SMS User Consent API.
Well-explained documentation can be found here. (Contains further links to a reference implementation that pretty much works out of the box, so I'm not including that code here.)
Be sure to choose the appropriate API for your use case.
I am trying to use firebase phone auth in my
app with an emulator. I have a testing number set up in firebase, but everytime i try to send a verification code, I get the same error: PhoneAuthProvider: Sms auto retrieval timed-out. how do i fix this?*
class PhoneAuth : AppCompatActivity() {
private var verificationIdGlobal: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_phone_auth)
b_phone_send.setOnClickListener {
val phoneNumber = et_phone_phone.text.toString().trim()
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
callbacks) // OnVerificationStateChangedCallbacks
}
b_phone_sign_in.setOnClickListener {
val verificationCode = et_phone_verification_code.text.toString().trim()
verificationIdGlobal?.let {
val credential = PhoneAuthProvider.getCredential(it, verificationCode)
addPhoneNumber(credential)
}
}}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks(){
override fun onVerificationCompleted(phoneAuthCredential: PhoneAuthCredential) {
phoneAuthCredential.let {
addPhoneNumber(phoneAuthCredential)
}
TODO("Not yet implemented")
}
override fun onVerificationFailed(exception: FirebaseException) {
Log.d("phone", "$exception")
TODO("Not yet implemented")
}
override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(verificationId, token)
verificationIdGlobal = verificationId
}
}
private fun addPhoneNumber(phoneAuthCredential: PhoneAuthCredential){
FirebaseAuth.getInstance().currentUser?.updatePhoneNumber(phoneAuthCredential)?.addOnCompleteListener {task ->
if (task.isSuccessful){
Log.d("Phone", "task successful")
}
else{
Log.d("Phone", "${task.exception}")
}
}
}
as per my understanding, if you added a phone number as a test number in Firebase console then it will never send a SMS to it, if you did so, then make sure you remove the number from test numbers list in firebase console >> Authentication >> Sign-in method >> Phone >> Phone numbers for testing, then try sending verification SMS to it.
You need to disable developer options and restart your smartphone. Now collect the project and install it on your smartphone, you will receive SMS.