FrangSierra/RxFirebase

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}))
  1. Check login status just after signInWithCredential function

FirebaseAuth.getInstance (). CurrentUser == null why?

  1. 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?

  1. 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