In the previous chapters we have implemented lots of features. In our app, we can register and login in using email and password, we can logout, and reset the password. But there are other possiblities to accelerate the authentication process. Using Facebook we can login and register with one click. In this chapter we are going to implement this feature.
If you haven’t done the previous chapters, then from GitHub you can download the starter project for this chapter.
As we have done in case of the email authentication, we have to enable the Facebook authentication in Firebase as well. So open your Firebase account, where you have the registered project. There select from the left sidebar menu the “Authentication”, then “Sing-in method”. Here you should see a line for Facebook. If you move your mouse to this line, then at the end of if should be a pen.
Click on the pen icon and enable Facebook.
We have to fill out the 2 fields. We can get the “App ID” and the “App secret” from the developer page of Facebook.
To use Facebook as an authentication method, we have to create there a developer account. For this click on the link below and create a Facebook acount if you still don’t have.
In the popup window you should provide the name of the app and a contact email.
If you are done, then click on the “Create App Id” button.
After thet the app will be created. In Firebase we have to provide the “App Id”, what we can find at the top of the window. Copy it and paste into Firebase.
The “App secret” is also available. If you click in the left menu on the “Settings” option, then 2 more options will be visible, where select the “Basic” menu.
Click on the “Show” button and in a popup window you should provide the password of your Facebook acount. After that, the “App secret” will be visible.
Copy it and paste it again into Firebase.
With this 2 code the story is still not finished. The process has just begun, because we have to set up the Facebook login.
To do that, click on the “Dashboard” menu, what is located in the left sidebar menu. Here in the center of the window should be the “Facebook Login” card. It has a “Set Up” button at the bottom right corner. Click on it.
From the possible choices select “Android” and the steps of the implementation gonna be visible. 10 steps, but don’t be afraid, all of them are easy steps.
1. Download the Facebook SDK for Android
We are going to skip this first step, so click on the “Next” button.
2. Import the Facebook SDK
In the next step first copy the line of “mavenCentral()”, then open the project in Android Studio. There open from the Gradle Scripts, then the Project build.gradle. Here will be the “buildscript” which contains “repositories”. Paste here the “mavenCentral()”. then click on “Sync now”.
Previously we have added the Facebook dependency to our app, so we can skip this part.
We will skip the imports as well. So click again on the “Next” button.
3. Tell Us about Your Android Project
In this section first we have to provide the package name of our project. You can find it, if you open from the manifest folder the AndroidManifest.xml file. Directly in the <manifest> tag should be the line of the package.
In my case it look like this:
package=“com.inspirecoding.firebaseauthdemo”
Copy the package and past it into Facebook.
Next is the default activity class name. It will be the path of the MainActivity::class. If you open this activity, then in the first line you should find the name of the package, which starts with the keyword of “package”. Copy it and paste it into Facebook, then extend it with the name of “MainActivity”.
In my case it look like this:
com.inspirecoding.firebaseauthdemo.ui.MainActivity
Click Save!
A window will popup. It says thet “There was a problem verifying package name”. Just click on the “Use this package name” button.
Click Continue!
4. Add Your Development and Release Key Hashes
To generate the valid Key Hash for the Facebook authentication we have more possibilities. From them, we are going to use 2 solutions, because sometimes they get back different Key Hashes.
If the Key Hash is wrong, then the Facebook authentication won’t work.
Use a method
We are going to use first a method to get the Key Hash. So just copy and past this method into the source of the SplashActivity::class, after to the onCreate() method.
Be careful to import the correct package, because we need in this case this package: “android.util.Base64”. Otherwise you will get error messages.
private fun printKeyHash()
{
try
{
val info = packageManager.getPackageInfo("com.pazpeti.runningapp", PackageManager.GET_SIGNATURES)
for(signature in info.signatures)
{
val messageDigest = MessageDigest.getInstance("SHA")
messageDigest.update(signature.toByteArray())
Log.i("printKeyHash", Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))
}
}
catch (exception: PackageManager.NameNotFoundException)
{
Toast.makeText(this, exception.toString(), Toast.LENGTH_LONG).show()
}
catch (exception: NoSuchAlgorithmException)
{
Toast.makeText(this, exception.toString(), Toast.LENGTH_LONG).show()
}
}
printKeyHash()
I won’t explaine the whole method line by line. What matters is that, we will get back the Key Hash in a log message with the tag of “printKeyHash”.
Call this function inside of the onCreate() method and run the app.
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
printKeyHash()
...
}
call of printKeyHash() from onCreate()
After a successful run open in Android Studio the Logcat and search for the tag. When everthing was ok, then there should be the Key Hash.
Copy the Key Hash and past it into Facebook.
Convert SHA-1 to Key Hash
In the second solution we won’t use any codes. Here we are going to get from Android Studio the project SHA-1 code, then using a website we gonna convert it to Key Hash.
This will open at the bottom of Android Studio a new window and it will generate same information about our project. Here you can find the SHA-1 code, copy it.
Now open the below link.
Before we continue, we have to set back Android Studio from the “signingReport” to “app”, because you will be surprised, why you can’t run the app.
Now you can click on Facebook on the Continue button.
5. Enable Single Sign On for Your App
Just click “Next”!
6. Edit Your Resources and Manifest
In this step we are going to add first 2 strings to the strings.xml file, which is located in the “res”, then in the “values” folder. So open it and copy-paste this the 2 strings from Facebook.
That’s it!
We won’t need the other steps, because we are going to implement them a little bit differently, escpecially we won’t use the Facebook Login Button.
After the creation of the Facebook Login, we are going to provide the OAuth Redirect URI as well.
You can find this URI inside of the Firebase’s project of the app. When you clicked on the pen icon at the line of Facebook, a popup window came for. Remember?
There we provided the App ID and the App Secret. Below them is the URI. So copy the link.
OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords.
In Facebook go to the “Products” part of the left sidebar and expand the list. There is the menu of “Settings”, click on it. Here will be the line of “Valid OAuth Redirect URIs”. Paste there the link and click on the “Save Changes” button at the bottom of the window.
After the grant of the Facebook authentication, finally we can start to implement the functions in our app. As before, we are going to add a mothod first to the UserRepository:interface.
So open the UserRepository::interface and add this new function there.
suspend fun signInWithCredential(
authCredential: AuthCredential
): Result<AuthResult?>
signInWithCredential()
This function will get back a Result, which contains an AuthResult from Firebase. This class will provide us the id of the registered user.
We will implement this method in the UserRepositoryImpl::class as well. So press control+o, and generate this method. In the body of this function, we gonna call on the FirebaseAuth class the signInWithCredential() method. As the only argument, we will have an AuthCredential, which will be provided by the Facebook authentication.
We have to wait until the call will be finished. So we are going to call on it again the await() extension function.
override suspend fun signInWithCredential(
authCredential: AuthCredential
): Result<AuthResult?>
{
return firebaseAuth
.signInWithCredential(authCredential)
.await()
}
signInWithCredential()
The longer part of the Facebook authentication will be in the FirebaseViewModel::class.
First we will create a member variable there, but we will give it the final value later.
private var callbackManager: CallbackManager? = null
The name of this method will be signInWithFacebook and it will have one argument, the instance of the caller Activity.
fun signInWithFacebook(activity: Activity)
{
launchDataLoad {
callbackManager = CallbackManager.Factory.create()
LoginManager
.getInstance()
.logInWithReadPermissions(
activity,
Arrays.asList("email", "public_profile"))
LoginManager.getInstance().registerCallback(callbackManager, object : FacebookCallback
{
override fun onSuccess(result: LoginResult?)
{
val credential = FacebookAuthProvider.getCredential(result?.accessToken?.token!!)
viewModelScope.launch {
when(val result = userRepository.signInWithCredential(credential))
{
is Result.Success -> {
result.data?.user?.let { user ->
val _user = user.displayName?.let {
createUserObject(
user,
it
)
}
_user?.let {
createUserInFirestore(_user, activity)
}
}
}
is Result.Error -> {
Log.e(TAG, "Result.Error - ${result.exception.message}")
_toast.value = result.exception.message
}
is Result.Canceled -> {
Log.d(TAG, "Result.Canceled")
_toast.value = activity.applicationContext.getString(R.string.request_canceled)
}
}
}
}
override fun onError(error: FacebookException?)
{
Log.e(TAG, "Result.Error - ${error?.message}")
_toast.value = error?.message
}
override fun onCancel()
{
Log.d(TAG, "Result.Canceled")
_toast.value = activity.applicationContext.getString(R.string.request_canceled)
}
})
}
}
signInWithFacebook()
The whole body will be inside of the launchDataLoad {}. Remember, this will show for the user a ProgressBar during the registration process.
Then we will add value for the CallbackManager.
callbackManager = CallbackManager.Factory.create()
For the registration, we have to tell for Facebook which data we want to use for the registration. This line will do this:
LoginManager
.getInstance()
.logInWithReadPermissions(
activity,
Arrays.asList("email", "public_profile"))
logInWithReadPermissions()
Then comes the registration of the callback. On the FacebookCallback object, we have to call 3 methods, which will provide us the result of the process.
onSuccess method – Result.Success
In this case, the result variable will provide us the registered user, if we call on it result.data.user. Because the data and the user can be null, we gonna use the null safe .let lambda first on result.data.user, then on the user.displayName, which will contain the name of the user from Facebook. In this second .let lambda we are going to call the createUserObject() method, which will create for us the User object.
fun createUserObject(
firebaseUser: FirebaseUser,
name: String,
profilePicture: String = ""
): User
{
val currentUser = User(
id = firebaseUser.uid,
name = name,
profilePicture = profilePicture
)
return currentUser
}
createUserObject
The user variable is needed for the Firestore query. We are going to create there a document for the user in the “users” collection, when we won’t have any null values in the user variable, what we created now.
onSuccess method – Result.Success
In this case we will notify the user about the error.
onError method
In this method we will do the same like in case of the “onSuccess – Result.Error”.
onSuccess method – Result.Canceled
Same here again, like in “onSuccess – Result.Canceled”.
Our task consists of two subtasks. We should first implement the click listeren for the Facebook Button, and call there the method signInWithFacebook() from the FirebaseViewModel::class.
iv_register_facebook.setOnClickListener {
firebaseViewModel.signInWithFacebook(this)
}
setOnClickListener
When we click on the Button, then a popup window will be shown. Here we can select which account we want to use for the registration.
After the selection, the activity will get back from the Dialog the result in the onActivityResult() method. It is inherited from the superclass.
Until now we haven’t used this method. This method will be called also, when we start a new activity and we want to get back some data from it.
For instance, we want to select an image for our profile. In this case we will get back the data about image in this method.
You can find more information about getting a result from an activity under the link.
So override this method. Here we are going to have a method from the FirebaseViewModel::class, becasue we have to provide it the result, but we still haven’t implemented it yet.
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?)
{
super.onActivityResult(requestCode, resultCode, data)
firebaseViewModel.onActivityResult(
requestCode,
resultCode,
data,
this)
}
onActivityResult
So now go back to the FirebaseViewModel::class and past this function there.
fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?,
activity: Activity)
{
callbackManager?.onActivityResult(
requestCode,
resultCode,
data)
}
onActivityResult in the FirebaseViewModel::class
This method will provide for the Facebook’s callbackManager the result of the authentication. If it was ok, then the user will be redirected to the MainActivity::class and there the user’s name will be written in the TextView.
In the LoginActivity::class we are going to call also the signInWithFacebook() method from the FirebaseViewModel::class. Don’t worry, the user won’t be saved more times then one in Firebase nor in Firestore. Why?
In Firebase for an email only one registration is possible. If it does exist, then in case of Facebook authentication, the user will be logged in.
In Firestore we create the document of the user with the id from the Firebase authentication. Firestore won’t create one more document with the same id, because they are always unique.
iv_login_facebook.setOnClickListener {
firebaseViewModel.signInWithFacebook(this)
}
setOnClickListener
As we have done in case of the RegisterActivity::class, here we have to catch the result of the request in the onActivityResult() method also. So just copy and paste there this function.
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?)
{
super.onActivityResult(requestCode, resultCode, data)
firebaseViewModel.onActivityResult(
requestCode,
resultCode,
data,
this)
}
onActivityResult()
Now run the app on a device. Don’t forget, that you have to have a valid Facebook account to test the authentication. Later on you can delete the registration from Firebase.
The source code is available on GitHub
I hope the description was understandable and clear. But, if you have still questions, then leave me comments below! 😉
Have a nice a day! 🙂
Subscribe to receive exclusive content and notifications