Closed MauricioDomenech closed 2 years ago
Some result or maybe progress about Compose?
Hi there! we're working on a proposal to use login with Jetpack Compose. We're now testing the solution and we'll share the code soon. Thanks for starting this discussion.
Hi again. We continue working on a sample app that showcases login, share and appEvents but I wanted to provide you some code to unblock you and get your feedback.
The easiest way to add Facebook login to your app is to use LoginButton
. It can be wrapped it in an AndroidView
to create a composable:
@Composable
fun WrappedLoginButton() {
AndroidView(
factory = { context -> LoginButton(context) }
)
}
If you prefer to use a custom button, the LoginManager
class provides a set of methods that can be called from the composable. Bear in mind that, if you are passing an activity which supports androidx activity result APIs(e.g: ComponentActivity
, FragmentActivity
, AppCompactActivity
,.. ), there is no need to override onActivityResult()
in your activity.
val login = {
LoginManager.getInstance().logIn(this, CallbackManager.Factory.create(), listOf("email"))
}
val logout = {
LoginManager.getInstance().logOut()
}
@Composable
fun CustomLoginButton(profile: Profile?, login: () -> Unit, logout: () -> Unit) {
val buttonText = if (profile == null) "Continue with Facebook" else "Log out"
val onClick = if (profile == null) login else logout
Button(onClick = onClick) {
Text(text = buttonText)
}
}
Both implementations launch a Facebook Activity when clicked. If you want to observe to changes in the profile(when a user logs in or logs out) the ProfileTracker
can help with ir. The following code shows how to use this tracker from a ViewModel.
class LoginViewModel: ViewModel() {
private val profileTracker =
object : ProfileTracker() {
override fun onCurrentProfileChanged(oldProfile: Profile?, currentProfile: Profile?) {
if (currentProfile != null) this@LoginViewModel.updateProfile(currentProfile)
else this@LoginViewModel.resetProfile()
}
}
private val _profileViewState = MutableLiveData(ProfileViewState(Profile.getCurrentProfile()))
val profileViewState: LiveData<ProfileViewState> = _profileViewState
override fun onCleared() {
profileTracker.stopTracking()
super.onCleared()
}
private fun updateProfile(profile: Profile) {
_profileViewState.value = _profileViewState.value?.copy(profile = profile)
}
private fun resetProfile() {
_profileViewState.value = _profileViewState.value?.copy(profile = null)
}
}
@Immutable
data class ProfileViewState(
val profile: Profile? = null
)
I created a sample app in this repo(https://github.com/xilosada/ComposeSample). Please let me know if this solution works for you.
Thank you very much, I will try to integrate it tomorrow and let you know.
Good, its work How i can check for good auth for navigation to another view?
I mean, how I can use method login and logout from ViewModel?
Mb we can use rememberLauncherForActivityResult for login?
@Programistich You can directly call LoginManager.getInstance().logIn
and LoginManager.getInstance().logout
to do login and logout as it's shown in https://github.com/facebook/facebook-android-sdk/issues/1018#issuecomment-954060470.
For the login methods that receive a callback manager as its parameter, its first parameter is an instance of ActivityResultRegistryOwner. Facebook SDK will handle all stuffs for registering the launcher for activity result. So you don't need to call rememberLauncherForActivityResult
.
I mean that the login and logout functions are created in the activity, and I want to get a way to create these functions in the viewmodel In my case, this is a custom compose button, pressing which works out the view model If you can tell me how to use rememberLauncherForActivityResult, I would be grateful
Hi @Programistich. Unfortunately, we cannot support directly using rememberLauncherForActivityResult
due to the lifecycle restrictions. For login/logout methods created in the activity, they should be able to access the activity as the context so you can call LoginManager.getInstance().logIn
and LoginManager.getInstance().logout
. These two methods will handle the details of the activity result registration.
Hi again. We continue working on a sample app that showcases login, share and appEvents but I wanted to provide you some code to unblock you and get your feedback.
The easiest way to add Facebook login to your app is to use
LoginButton
. It can be wrapped it in anAndroidView
to create a composable:@Composable fun WrappedLoginButton() { AndroidView( factory = { context -> LoginButton(context) } ) }
If you prefer to use a custom button, the
LoginManager
class provides a set of methods that can be called from the composable. Bear in mind that, if you are passing an activity which supports androidx activity result APIs(e.g:ComponentActivity
,FragmentActivity
,AppCompactActivity
,.. ), there is no need to overrideonActivityResult()
in your activity.val login = { LoginManager.getInstance().logIn(this, CallbackManager.Factory.create(), listOf("email")) } val logout = { LoginManager.getInstance().logOut() } @Composable fun CustomLoginButton(profile: Profile?, login: () -> Unit, logout: () -> Unit) { val buttonText = if (profile == null) "Continue with Facebook" else "Log out" val onClick = if (profile == null) login else logout Button(onClick = onClick) { Text(text = buttonText) } }
Both implementations launch a Facebook Activity when clicked. If you want to observe to changes in the profile(when a user logs in or logs out) the
ProfileTracker
can help with ir. The following code shows how to use this tracker from a ViewModel.class LoginViewModel: ViewModel() { private val profileTracker = object : ProfileTracker() { override fun onCurrentProfileChanged(oldProfile: Profile?, currentProfile: Profile?) { if (currentProfile != null) this@LoginViewModel.updateProfile(currentProfile) else this@LoginViewModel.resetProfile() } } private val _profileViewState = MutableLiveData(ProfileViewState(Profile.getCurrentProfile())) val profileViewState: LiveData<ProfileViewState> = _profileViewState override fun onCleared() { profileTracker.stopTracking() super.onCleared() } private fun updateProfile(profile: Profile) { _profileViewState.value = _profileViewState.value?.copy(profile = profile) } private fun resetProfile() { _profileViewState.value = _profileViewState.value?.copy(profile = null) } } @Immutable data class ProfileViewState( val profile: Profile? = null )
I created a sample app in this repo(https://github.com/xilosada/ComposeSample). Please let me know if this solution works for you.
Hi @xilosada @linmx0130,
Thanks for the solution.
But it does not work when the activity hosting the WrappedLoginButton
/CustomLoginButton
is destroyed by OS.
You can reproduce it by enabling Don't keep activities
in Developer options
.
Unfortunately, we cannot support directly using
rememberLauncherForActivityResult
due to the lifecycle restrictions.
Out of curiosity what are these restrictions? The docs for the contract api say that contracts should be registered unconditionally during creation which isn't what the SDK is doing here. Not having the contract exposed also means we always need to have a special solution for Facebook to call the login SDK method to trigger navigation, while we can handle all others the same way
@gabrielittner The restriction is indeed that "contracts should be registered unconditionally during creation". The original APIs of the LoginManager
don't expose the contracts because there wasn't activity result contracts before. We have to add some condition statement to check whether activity result API is available to be back-compatible with legacy activities, which breaks the restriction.
If you do think that's important, could you open a new feature request issue for it?
Please follow this sample for login supports in Jetpack Compose.
@linmx0130 thanks for the sample. I followed the instructions in strings.xml, but my app does not show a client token. Do you know if I can still use this
?
Hi @ColtonIdle, thanks for using Facebook SDKs! Could you send a request to Developer Support Funnel to seek help on it? It seems a problem on the developer portal and they should be able to help you to address it.
@linmx0130 i have tried your example but it does not work. I log in on my fb and get back return to app but not any of those Toast shows up. I have setup all app_id, client_id etc . Do you maybe have an idea why it does not trigger register callback when back to app?
How can I get accessToken or result onSuccess response this code ? Does this code only get the user's first and last name? I also need an access token, what can I do?
Not sure if this will help @Enes481 as I haven't read the article, but I saw this pop up from someone I follow on twitter: https://www.composables.co/blog/firebase-auth-facebook
Checklist before submitting a feature request
Goals
I want to integrate the FB Login SDK in an app with Jetpack Compose
Expected results
We need Facebook to update the documentation and also there are examples with Jetpack Compose, I am developing a new app on Android and I can't implement the Login with Facebook because there is no documentation about this!
Code samples & details