android - 使用 Jetpack Compose 登录 Facebook

标签 android facebook android-jetpack-compose

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

现在我必须实现 Facebook 登录,但我被卡住了,因为他们仍在使用已弃用的 onActivityResult 而不是新的契约(Contract) api。

这是我正在尝试的文档 follow ,我们将不胜感激。

谢谢大家

最佳答案

您必须等待this issue待解决。

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

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 逻辑移动到 View 模式并通过,然后您必须创建自己的回调管理器,如下所示:

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")
        }
    }
}

您也可以尝试构建 this fork , 它包含来自 this pull request 的更改.它增加了对合约api的支持,目前还没有被接受。仔细检查更改,这不是官方的!

关于android - 使用 Jetpack Compose 登录 Facebook,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69107068/

相关文章:

android - 从服务访问 UI 线程处理程序

php - 如何从我的应用程序中获取 facebook 用户 ID?

android - 适用于 Android 的 AutoLink 撰写文本

kotlin - Jetpack Compose中有没有类似SwiftUI中 'ZStack'分组的功能

android - 如果超出行宽,如何将子项布局在多行中?

php - Google PlayIntegrity API - 通过 PHP 验证 token

Android:基于屏幕尺寸的不同图像

ios - 在 iOS 版 Air 应用程序中邀请 facebook 好友

android - 尝试在低于最低 sdk 的设备上安装 apk 时出现“解析错误”

javascript - Facebook 爬虫目前是否在解析 DOM 之前解释 javascript?