Search code examples
androidfirebasefirebase-authenticationfirebaseuiaccountmanager

Add Account To Account Manager After Firebase Auth UI


I am trying to take WhatsApp's approach to contact lists, where I simply sync my app's contacts with the devices contacts. I am using Firebase as my Authentication Platform and Database (Firestore). I am using Firebase Auth UI for Phone Number Authentication.

What I would like to achieve is my In-App contacts list basically load with my device contacts ONLY if those contacts have my app installed as well. Just like WhatsApp does.

I have already read the official docs for AccountManager and seen a few tutorials like this one but cannot figure out how to put it all together.

Questions I have are:

  1. What exactly is the role of the AccountAuthenticator and for what purpose would a developer use it? Do I need an AccountAuthenticator for my use case? Do I just need to do AccountManager.addAccountExplicitly() and that's it?

  2. If I do need the whole API, how do I set it up with my Firebase Auth UI? The Auth UI is already handling the login flow and everything and I'm already storing a user object in Firestore.

  3. In AccountManager.addAccountExplicitly(accountName, accountType), what is Account Name supposed to be and Account Type supposed to be? Give an example.

Here Is My Current Code For Firebase Authentication:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_launch)
    tilName.visibility = View.GONE
    btnSignIn.visibility = View.GONE
    Handler().postDelayed({
        if (auth.currentUser == null) startActivityForResult(
            AuthUI.getInstance().createSignInIntentBuilder()
                .setAvailableProviders(listOf(AuthUI.IdpConfig.PhoneBuilder().build()))
                .setTheme(R.style.LauncherTheme).build(), rcSignIn
        )
        else startActivity(Intent(this, MainActivity::class.java))
    }, 1000)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == rcSignIn) {
        val response = IdpResponse.fromResultIntent(data)
        if (resultCode == Activity.RESULT_OK) {
            val user = auth.currentUser!!
            tilName.visibility = View.VISIBLE
            btnSignIn.visibility = View.VISIBLE
            btnSignIn.setOnClickListener {
                if (etName.text!!.isNotEmpty()) user.updateProfile(
                    UserProfileChangeRequest.Builder().setDisplayName(etName.text.toString()).build()
                ).addOnSuccessListener { addUser(user) }.addOnFailureListener {
                    Log.e("Update User Profile", "Failed To Update User Profile", it)
                } else snackBar("You haven't provided a valid name in the Text Field")
            }
        } else Log.i("User Sign In", "Sign-In Process Failed", response?.error!!)
    }
}

private fun addUser(user: FirebaseUser) {
    pbSigningUp.visibility = View.VISIBLE
    FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener {
        Log.i("Get FCM Token", "Device Token Retrieved Successfully: ${it.token}")
        db.collection("users").document(user.uid).set(User(user.displayName!!, user.phoneNumber!!, it.token))
            .addOnSuccessListener {
                Log.i("Add User", "New User Added Successfully: ${user.uid}")
                startActivity(Intent(this, MainActivity::class.java))
            }.addOnFailureListener { e -> Log.e("Add User Failed", "Failed To Add New User", e) }
    }.addOnFailureListener { Log.e("Device FCM Token", "Failed To Retrieve Device Token", it) }
}

After my app returns from Firebase Auth UI, I ask him for his name and store everything in a user object on Firestore.


Solution

  • It seems the Account Authenticator is meant to be the interface between your application and your server, every time the user logs in. It serves the purpose of getting new Auth-Tokens and managing User Credentials with your server.

    Since, Firebase already does all that for me, it would seem that the Account Authenticator is not required. But it is. It is highly recommended to create a Stub Authenticator and a corresponding Authenticator Service (even if you're not going to use it). The code for which can be found here in the official Android Documentation.

    There isn't much after that. AccountManager.addAccountExplicitly() works just fine. To be safe I even extended the Activity to AccountAuthenticatorActivity and found no change in the way it functions - so it's completely fine to do so.

    As far as the question of accountName and accountType goes.

    • Account Name can be anything. Name, phone number, email... Whatever you want to identify your account by.
    • Account Type should generally be your app's package name.

    Hope this helps.