Created
March 2, 2025 10:34
-
-
Save tomleejumah/ecbb293b9e2c380bb9cce6093df45872 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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