使用 Jetpack Compose 登录 Facebook [英] Facebook login with Jetpack Compose

查看:83
本文介绍了使用 Jetpack Compose 登录 Facebook的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始着手一个 100% 使用 Jetpack compose 编写的新项目,这意味着我们没有任何片段,而且我们也遵循单一活动模式.

I started working on a new project that is 100% written with Jetpack compose, meaning we don't have any fragments and we're also following the Single activity pattern.

现在我必须实现 Facebook 登录,但我被卡住了,因为他们仍在使用已弃用的 onActivityResult 而不是新的合同 API.

Now I have to implement the Facebook login but I'm stuck since they're still using the deprecated onActivityResult instead of the new contract api.

这是我正在尝试关注的文档,任何将不胜感激.

Here's the documentation that I'm trying to follow, any help would be greatly appreciated.

谢谢大家,

推荐答案

你必须等待 这个问题有待解决.

You have to wait this issue to be resolved.

现在,您可以使用 CompositionLocalProvidercallbackManager 从您的活动传递到 Compose 树,如下所示:

For now you can pass callbackManager down from your activity to the Compose tree using CompositionLocalProvider, like this:

val LocalFacebookCallbackManager =
    staticCompositionLocalOf<CallbackManager> { error("No CallbackManager provided") }

class MainActivity : FragmentActivity() {
    private var callbackManager = CallbackManager.Factory.create();

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Theme {
                CompositionLocalProvider(
                    LocalFacebookCallbackManager provides callbackManager
                ) {
                    LoginScreen()
                }
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        callbackManager.onActivityResult(requestCode, resultCode, data)
        super.onActivityResult(requestCode, resultCode, data)
    }
}

@Composable
fun LoginScreen() {
    val callbackManager = LocalFacebookCallbackManager.current
    DisposableEffect(Unit) {
        LoginManager.getInstance().registerCallback(
            callbackManager,
            object : FacebookCallback<LoginResult> {
                override fun onSuccess(loginResult: LoginResult) {
                    println("onSuccess $loginResult")
                }

                override fun onCancel() {
                    println("onCancel")
                }

                override fun onError(exception: FacebookException) {
                    println("onError $exception")
                }
            }
        )
        onDispose {
            LoginManager.getInstance().unregisterCallback(callbackManager)
        }
    }
    val context = LocalContext.current
    Button(onClick = {
        LoginManager.getInstance()
            .logInWithReadPermissions(context.findActivity(), Arrays.asList("public_profile"));
    }) {
        Text("FB Login")
    }
}

fun Context.findActivity(): Activity? = when (this) {
    is Activity -> this
    is ContextWrapper -> baseContext.findActivity()
    else -> null
}


更通用的解决方案是将 facebook 逻辑移动到视图模式,然后传递,然后您必须创建自己的回调管理器,如下所示:


More general solution is moving facebook logic into a view mode, and passing, then you have to create your own callback manager, something like this:

ActivityResultCallbackManager.kt

val LocalActivityResultCallbackManager =
    staticCompositionLocalOf<ActivityResultCallbackManager> { error("No ActivityResultCallbackManager provided") }

interface ActivityResultCallbackI {
    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean
}

class ActivityResultCallbackManager {

    private val listeners = mutableListOf<ActivityResultCallbackI>()

    fun addListener(listener : ActivityResultCallbackI) {
        listeners.add(listener)
    }

    fun removeListener(listener : ActivityResultCallbackI) {
        listeners.remove(listener)
    }

    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) : Boolean =
        listeners.any { it.onActivityResult(requestCode, resultCode, data) }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private var callbackManager = ActivityResultCallbackManager()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)
        setContent {
            Theme {
                CompositionLocalProvider(
                    LocalActivityResultCallbackManager provides callbackManager
                ) {
                    LoginScreen()
                }
            }
        }
    }

    override fun onActivityResult(
        requestCode: Int,
        resultCode: Int,
        data: Intent?
    ) {
        if (!callbackManager.onActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

FacebookLoginViewModel.kt

class FacebookLoginViewModel : ViewModel(), ActivityResultCallbackI {
    sealed class LoginState {
        object Initial: LoginState()
        object Processing: LoginState()
        data class Success(val loginResult: LoginResult): LoginState()
        data class Error(val exception: FacebookException): LoginState()
    }

    private var callbackManager = CallbackManager.Factory.create()
    var state by mutableStateOf<LoginState>(LoginState.Initial)
        private set

    init {
        LoginManager.getInstance().registerCallback(
            callbackManager,
            object : FacebookCallback<LoginResult> {
                override fun onSuccess(loginResult: LoginResult) {
                    state = LoginState.Success(loginResult)
                }

                override fun onCancel() {
                    state = LoginState.Initial
                }

                override fun onError(exception: FacebookException) {
                    state = LoginState.Error(exception)
                }
            }
        )
    }

    override fun onCleared() {
        super.onCleared()
        LoginManager.getInstance().unregisterCallback(callbackManager)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean =
        callbackManager.onActivityResult(requestCode, resultCode, data)

    fun login(context: Context) {
        state = LoginState.Processing
        LoginManager.getInstance()
            .logInWithReadPermissions(context.findActivity(), Arrays.asList("public_profile"));
    }
}

LoginScreen.kt

@Composable
fun LoginScreen() {
    val viewModel: FacebookLoginViewModel = viewModel()
    val callbackManager = LocalActivityResultCallbackManager.current
    DisposableEffect(Unit) {
        callbackManager.addListener(viewModel)
        onDispose {
            callbackManager.removeListener(viewModel)
        }
    }
    val context = LocalContext.current
    Column {
        Text(viewModel.state.toString())
        Button(onClick = {
            viewModel.login(context)
        }) {
            Text("FB Login")
        }
    }
}


您也可以尝试构建这个fork,它包含更改来自这个拉取请求.它增加了对合约 api 的支持,尚未被接受.仔细检查更改,这不是官方的!


Also you can try building this fork, it contains changes from this pull request. It adds support of contract api, and is not yet accepted. Check out changes carefully, it's not official!

这篇关于使用 Jetpack Compose 登录 Facebook的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆