1

Currently, I am trying to implement facebook-login in combination with cloud firestore inside my app. Everything works fine like it should (login, registration, Firebase.auth.currentUser != null).

The only problem I have is that when I log out of my app and then log in again with facebook I get the message "Up to now you have registered with xyz via Facebook. Do you want to continue."

I don't know why this message is coming. Even deleting the created facebook account from my cloud-firestore did not resolve the problem.

Here is a screenshot:

enter image description here

My Login Process

Fragment

class UserLogInRegistrationFragment : Fragment(R.layout.fragment_user_log_in_registration) {
    private val viewModel: LoginViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Register Facebook Callback
        viewModel.onEvent(LoginRegistrationEvent.RegisterFacebookCallback)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initExternalLogins()
        observeSignInOptions()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        viewModel.onEvent(LoginRegistrationEvent.SignInWithFacebook(requestCode, resultCode, data))
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // Unregister Facebook Callback
        viewModel.onEvent(LoginRegistrationEvent.UnregisterFacebookCallback)
    }
    
    private fun initExternalLogins() {
        facebookSignInBtn.setOnClickListener { viewModel.onEvent(LoginRegistrationEvent.OnStartFacebookSignIn) }
    }
    
    private fun observeSignInOptions() {
        viewModel.signInOption.observe(viewLifecycleOwner) { event ->
            when(event) {
                is SignInOption.FacebookSignIn -> { 
                    // Starting Login Process. This will be executed by the viewmodel
                    facebookManager().logInWithReadPermissions(this, listOf("email", "public_profile")) 
                }
            }
        }
    }
}

Viewmodel

class LoginViewModel @Inject constructor(
    private val loginValidator: LoginValidator
) : ViewModel() {
    val signInOption = loginValidator.signInOption
    val signInResult = loginValidator.signInResult

    fun onEvent(event: LoginRegistrationEvent) {
        when (event) {
            LoginRegistrationEvent.RegisterFacebookCallback -> viewModelScope.launch { loginValidator.registerFacebookCallback() }
            LoginRegistrationEvent.UnregisterFacebookCallback -> loginValidator.unregisterFacebookCallback()
            
            LoginRegistrationEvent.OnStartFacebookSignIn -> loginValidator.startFacebookSignIn()
            
            is LoginRegistrationEvent.SignInWithFacebook -> viewModelScope.launch {
                loginValidator.handleFacebookSignInActivity(event.requestCode, event.resultCode, event.data)
            }
        }
    }
}

LoginValidator (Use Case)

class LoginValidator @Inject constructor(
    private val loginRepository: LoginRepository,
) {
    private val _signInOption = MutableLiveData<SignInOption>()
    val signInOption: LiveData<SignInOption> get() = _signInOption

    private val _signInResult = MutableLiveData<LoginStateEvent>()
    val signInResult: LiveData<LoginStateEvent> get() = _signInResult

    fun startFacebookSignIn() {
        _signInOption.value = SignInOption.FacebookSignIn
    }

    suspend fun registerFacebookCallback() {
        loginRepository.signInWithFacebook().collect {
            _signInResult.value = it
        }
    }

    fun unregisterFacebookCallback() {
        loginRepository.unregisterFacebookCallback()
    }

    fun handleFacebookSignInActivity(requestCode: Int, resultCode: Int, data: Intent?) {
        loginRepository.handleFacebookSignInActivity(requestCode, resultCode, data)
    }

    fun signOut() = loginRepository.signOutUser()
}

LoginRepository

class LoginRepositoryImpl @Inject constructor(
    @ApplicationContext private val context: Context,
    private val callbackManager: CallbackManager,
    private val dbAuth: FirebaseAuth,
    private val dbFirestore: FirebaseFirestore
) : LoginRepository {

    override fun isUserLogedIn(): Boolean = when (dbAuth.currentUser) {
        null -> false
        else -> true
    }
    
    override fun signOutUser() {
        dbAuth.signOut()
        facebookManager().logOut()
    }
    
    @ExperimentalCoroutinesApi
    override suspend fun signInWithFacebook(): Flow<LoginStateEvent> = flow {
        val result = facebookManager().registerMCallback(callbackManager)
    
        emit(LoginStateEvent.Loading(context.getString(R.string.login_registration_progress_verify_facebook)))
        val credential = FacebookAuthProvider.getCredential(result.accessToken.token)
    
        emit(LoginStateEvent.Loading(context.getString(R.string.login_registration_progress_loggin_in)))
        dbAuth.signInWithCredential(credential).await()
    
        emit(LoginStateEvent.Loading(context.getString(R.string.login_regisration_progress_verifiy_rsb)))
        createUserIfNotExist(
            User(
                eMail = dbAuth.currentUser!!.email ?: "",
                lastName = splitToLastName(dbAuth.currentUser!!.displayName) ?: "",
                firstName = splitToFirstName(dbAuth.currentUser!!.displayName) ?: "",
                oAuth = OAuth.FACEBOOK
            )
        )
    
        emit(LoginStateEvent.LoggedIn)
    }.catch { e ->
        emit(convertExceptionToState(e as Exception))
    }
    
    override fun handleFacebookSignInActivity(requestCode: Int, resultCode: Int, data: Intent?) {
        callbackManager.onActivityResult(requestCode, resultCode, data)
    }
    
    override fun unregisterFacebookCallback() {
        facebookManager().unregisterCallback(callbackManager)
    }

Extension Function for Facebook Login

@ExperimentalCoroutinesApi
suspend fun LoginManager.registerMCallback(
    manager: CallbackManager
) = suspendCancellableCoroutine<LoginResult> { cont ->
    val callback = object : FacebookCallback<LoginResult> {
        override fun onSuccess(result: LoginResult) = cont.resume(result, cont::resumeWithException)

        override fun onCancel() { }

        override fun onError(error: FacebookException?) {
            error?.let { cont.resumeWithException(it) }
        }
    }
    registerCallback(manager, callback)
}

fun facebookManager(): LoginManager = LoginManager.getInstance()

Callback Manager

@Provides
fun provideCallbackManager(): CallbackManager = CallbackManager.Factory.create()

Sign-In Flow

https://i.stack.imgur.com/nNxN6.jpg

Dependencies I use

implementation "com.google.firebase:firebase-auth-ktx"
implementation 'com.facebook.android:facebook-login:8.1.0'

I have tried to stick to the cloud firestore documentation here and I've read this Stackoverflow post.

JM Gelilio
  • 3,482
  • 1
  • 11
  • 23
Andrew
  • 4,264
  • 1
  • 21
  • 65
  • How did you implement your facebook-login? What are the dependencies did you use and can you show some codes how did you log out and log-in the fb account or article/document/video that you are following for this? I'm also using facebook login but it didn't show that message when I logout and log in. – JM Gelilio Feb 09 '21 at 10:36

0 Answers0