Function signInWithCredential() not completed in success only onCompleted
CristianMG opened this issue · 2 comments
Hello
I am implementing phone authentication, after successfully implementing it I did it returned a FirebasePermissionDenied error but the second time it seemed to run correctly.
I tried to find out a bug reason what it was happening, and if the responsibility was this library envolve or firebase sdk.
I did the following checks.
Error code
The problem is that I try to write just after the login and in my rules that I have only authenticate users can write. this code throws an error
but why?
rxFirebaseRepository.signInWithCredential (credential)
.flatMapCompletable {
rxFirebaseRepository.setValue (FirebaseDatabase.getInstance (). reference.child (USERS) .child (it.user !!. uid), userMapper.mapToEntity (userModel))
} .andThen (Single.fromCallable ({userModel}))
- Check login status just after signInWithCredential function
FirebaseAuth.getInstance (). CurrentUser == null why?
- I tried implementate without this library looking at Google documentation
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 (TAG, "signInWithCredential: success");
FirebaseUser user = task.getResult (). GetUser ();
// ...
} else {
// Sign in failed, display a message and update the UI
Log.w (TAG, "signInWithCredential: failure", task.getException ());
if (task.getException () instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
This code works correctly, why?
- Looking at the differences between the implementation proposed by google and this library.
public class RxHandler <T> implements OnSuccessListener <T>, OnFailureListener, OnCompleteListener <T> {
private final MaybeEmitter <? super T> emitter;
private RxHandler (MaybeEmitter <? super T> emitter) {
this.emitter = emitter;
}
public static <T> void assignOnTask (MaybeEmitter <? super T> emitter, Task <T> task) {
RxHandler handler = new RxHandler (emitter);
task.addOnSuccessListener (handler);
task.addOnFailureListener (handler);
try {
task.addOnCompleteListener (handler);
} catch (Throwable var4) {
;
}
}
public void onSuccess (T res) {
if (res! = null) {
this.emitter.onSuccess (res);
} else {
this.emitter.onError (new RxFirebaseNullDataException ("Observables can not emit null values"));
}
}
public void onComplete (@NonNull Task <T> task) {
this.emitter.onComplete ();
}
public void onFailure (@NonNull Exception e) {
if (! this.emitter.isDisposed ()) {
this.emitter.onError (e);
}
}
}
I think that the problem is that the onSuccess function is called but the task is not completed so I call the writing function and this returns an error FirebasePermissionError
Looking at the documentation it seems that your implementation is correct but something is happening, I´ll leave this here to try to solve this small mystery.
At the moment I created my own envelope to solve this
return Maybe.create ({em ->
FirebaseAuth.getInstance (). SignInWithCredential (credential)
.addOnCompleteListener {
if (it.isSuccessful)
em.onSuccess (it.result)
else
em.onComplete ()
} .addOnFailureListener {
em.onError (it)
}
})
It seems that everything runs correctly
Regards
I'm using this method with the library on multiple production applications and it's working without any problem. I think that your problem is that you are during a flatmapCompletable
and calling FirebaseAuth().getCurrentUser
. Your FirebaseAuth.getInstance()
is returning null because Firebase doesnt update FirebaseAuth
automatically, it takes a few milliseconds because you are using the same threads with Rx that Firebase in the BG. I had this problem with other methods such as sendEmailVerification
or reload
.
What I suggest you is use the FirebaseUser
that your signInWithCredentials
returns you when it
calls onSuccess
for your next methods using a normal flatmap
Below you have an example from my app:
RxFirebaseAuth.fetchProvidersForEmail(authInstance, userData.email)
.flatMap { providerResult ->
//Check if the current provider is already associated to mark the result as a new account or not
when {
providerResult.providers!!.contains((credential.provider)) ->
return@flatMap RxFirebaseAuth.signInWithCredential(authInstance, credential).map { Pair(it, false) }
else -> return@flatMap RxFirebaseAuth.signInWithCredential(authInstance, credential).map { Pair(it, true) }
}
}
.subscribeOn(Schedulers.io())
.subscribe({ (authResult, isNewAccount) ->
val emailVerified = authResult.user.isEmailVerified
val user = authResult.user.toUser().copy(photoUrl = userData.photoUrl)
val providers = authResult.user.associatedProviders()
dispatcher.dispatchOnUi(CreateAccountCompleteAction(
user = user,
alreadyExisted = !isNewAccount,
emailVerified = emailVerified,
requestState = requestSuccess(),
associatedProviders = providers,
signInMethod = credential.provider))
if (!emailVerified) sendVerificationEmailToUser(authResult.user)
}, { error ->
dispatcher.dispatchOnUi(CreateAccountCompleteAction(
user = null,
requestState = requestFailure(error)))
})
Thanks you have reason, now run correctly