Skip to content

Instantly share code, notes, and snippets.

@tomleejumah
Created March 2, 2025 10:34
Show Gist options
  • Save tomleejumah/ecbb293b9e2c380bb9cce6093df45872 to your computer and use it in GitHub Desktop.
Save tomleejumah/ecbb293b9e2c380bb9cce6093df45872 to your computer and use it in GitHub Desktop.
class FacebookAuthHelper(private val activity: Activity) {
private val auth: FirebaseAuth = FirebaseAuth.getInstance()
private val callbackManager: CallbackManager = CallbackManager.Factory.create()
init {
// Initialize Facebook SDK if not already initialized
if (!FacebookSdk.isInitialized()) {
FacebookSdk.sdkInitialize(activity.applicationContext)
}
}
fun signIn(permissions: List<String> = listOf("email", "public_profile")) {
LoginManager.getInstance().logInWithReadPermissions(activity, permissions)
LoginManager.getInstance().registerCallback(callbackManager, object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult) {
Log.d(TAG, "facebook:onSuccess:$result")
handleFacebookAccessToken(result.accessToken)
}
override fun onCancel() {
Log.d(TAG, "facebook:onCancel")
}
override fun onError(error: FacebookException) {
Log.e(TAG, "facebook:onError", error)
}
})
}
fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// Pass the activity result back to the Facebook SDK
callbackManager.onActivityResult(requestCode, resultCode, data)
}
private fun handleFacebookAccessToken(token: AccessToken) {
Log.d(TAG, "handleFacebookAccessToken:$token")
val credential = FacebookAuthProvider.getCredential(token.token)
auth.signInWithCredential(credential)
.addOnCompleteListener(activity) { task ->
if (task.isSuccessful) {
// Sign in success
Log.d(TAG, "signInWithCredential:success")
val firebaseUser = auth.currentUser
firebaseUser?.let {
// Call Graph API to fetch additional user info then save user data
fetchGraphDataAndSaveUser(it, token)
}
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.exception)
onLoginErrorListeners.forEach { listener -> listener.invoke(task.exception ?: Exception("Unknown error")) }
}
}
}
private fun fetchGraphDataAndSaveUser(firebaseUser: FirebaseUser, token: AccessToken) {
val request = GraphRequest.newMeRequest(token) { jsonObject, _ ->
// Extract additional user info from the Graph API response
val firstName = jsonObject?.optString("first_name") ?: ""
val lastName = jsonObject?.optString("last_name") ?: ""
val displayName = jsonObject?.optString("name") ?: (firebaseUser.displayName ?: "")
val email = jsonObject?.optString("email") ?: (firebaseUser.email ?: "")
// Extract picture URL (using large image type)
val pictureUrl = jsonObject?.optJSONObject("picture")
?.optJSONObject("data")
?.optString("url") ?: (firebaseUser.photoUrl?.toString() ?: "")
val userData = UserData(
id = firebaseUser.uid,
email = email,
displayName = displayName,
firstName = firstName,
lastName = lastName,
photoUrl = pictureUrl,
idToken = token.token
)
// Save the updated user data to Firebase
saveUserToFirebase(userData)
onLoginSuccessListeners.forEach { listener ->
listener.invoke(userData)
}
}
// Request additional fields from the Graph API
val parameters = Bundle()
parameters.putString("fields", "id,name,first_name,last_name,email,picture.type(large)")
request.parameters = parameters
request.executeAsync()
}
private val onLoginSuccessListeners = mutableListOf<(UserData) -> Unit>()
private val onLoginErrorListeners = mutableListOf<(Exception) -> Unit>()
fun addOnLoginSuccessListener(listener: (UserData) -> Unit) {
onLoginSuccessListeners.add(listener)
}
fun addOnLoginErrorListener(listener: (Exception) -> Unit) {
onLoginErrorListeners.add(listener)
}
private fun extractUserData(firebaseUser: FirebaseUser, token: AccessToken): UserData {
return UserData(
id = firebaseUser.uid,
email = firebaseUser.email ?: "",
displayName = firebaseUser.displayName ?: "",
firstName = "", // We can get this from Graph API if needed
lastName = "", // We can get this from Graph API if needed
photoUrl = firebaseUser.photoUrl?.toString() ?: "",
idToken = token.token
)
}
fun getCurrentUser(): FirebaseUser? = auth.currentUser
fun isUserSignedIn(): Boolean = auth.currentUser != null
fun signOut(onComplete: () -> Unit) {
LoginManager.getInstance().logOut()
auth.signOut()
onComplete()
}
private fun saveUserToFirebase(
userData: UserData,
onSuccess: ((Boolean) -> Unit)?=null,
onError: ((Exception) -> Unit)?=null
) {
val usersRef = FirebaseDatabase.getInstance().getReference("users")
usersRef.child(userData.id).get().addOnCompleteListener { task ->
if (task.isSuccessful && task.result.exists()) {
Log.d("FirebaseDB", "User already exists, updating last login (Facebook)")
usersRef.child(userData.id).child("lastLogin").setValue(ServerValue.TIMESTAMP)
onSuccess?.invoke(true)
} else {
Log.d("FirebaseDB", "User does not exist, saving new user (Facebook)")
FirebaseUserHelper.saveOrUpdateUser(userData, usersRef, null, null)
}
}
}
companion object {
private const val TAG = "FacebookAuthHelper"
}
}
//inside oncreate
// Initialize the Facebook Auth Helper
facebookAuthHelper = new FacebookAuthHelper(requireActivity());
facebookAuthHelper.addOnLoginSuccessListener(userData -> {
// Handle successful login
Toast.makeText(requireContext(), "Logged in as " + userData.getDisplayName(), Toast.LENGTH_SHORT).show();
navigateToMainScreen();
return null;
});
facebookAuthHelper.addOnLoginErrorListener(exception -> {
// Handle login error
Toast.makeText(requireContext(), "Login failed: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
return null;
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Pass activity result to the Facebook helper
facebookAuthHelper.handleActivityResult(requestCode, resultCode, data);
}
//inside onview created
facebookLoginButton.setOnClickListener(v -> {
List<String> permissions = Arrays.asList("email", "public_profile");
facebookAuthHelper.signIn(permissions);
});
return view;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment