[解決済み] Jetpack ComposeでFacebookにログインする
2022-03-05 03:21:17
質問
このプロジェクトは100% Jetpack compose で書かれており、フラグメントはなく、また Single activity パターンに従っています。
Facebookのログインを実装しなければならないのですが、新しいコントラクトAPIではなく、非推奨のonActivityResultをまだ使っているので、行き詰っています。
以下は、私が試行錯誤しているドキュメントです。 フォロー 何かお手伝いいただけると幸いです。
皆さん、ありがとうございました。
解決方法は?
待つ必要があります。 この問題 が解決されます。
今のところ
callbackManager
を使用して、アクティビティからComposeツリーにダウンします。
CompositionLocalProvider
のようなものです。
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のロジックをビューモードに移動し、パスすることですが、このような独自のコールバックマネージャーを作成する必要があります。
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")
}
}
}
また、次のように構築することもできます。 このフォーク の変更点が含まれています。 このプルリクエスト . これはコントラクト API のサポートを追加するもので、まだ受理されていません。まだ正式なものではありませんので、注意深く変更点をチェックしてください。
関連
-
[解決済み】まだ警告が出る:設定 'compile' は時代遅れで 'implementation' に置き換わった。
-
[解決済み】Edit Textのandroid:ems属性とは何ですか?[重複しています]
-
[解決済み】java.lang.RuntimeException: アクティビティを開始できない ComponentInfo
-
[解決済み】このアクティビティは、すでにウィンドウ装飾によって提供されるアクションバーを持っています。
-
[解決済み】Android Studioでused import文がunused import文に指定されるのはなぜ?
-
[解決済み】'dependencies' を '(groovy.lang.Closure)' に適用できない。)
-
[解決済み】IllegalStateException: ViewPager で onSaveInstanceState の後にこのアクションを実行できません。
-
[解決済み] エラー - Android リソースのリンクに失敗しました (AAPT2 27.0.3 Daemon #0)
-
[解決済み] Gradle DSL メソッドが見つかりません:'compile()'
-
[解決済み] Facebookがブラウザに統合されたDeveloper Toolsを無効にする方法を教えてください。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】OnFragmentInteractionListenerを実装する方法
-
[解決済み] 現在のテーマでスタイル 'coordinatorLayoutStyle' を見つけることができませんでした。
-
[解決済み】Android Studio AVD - Emulator: 終了コード 1 でプロセスが終了
-
[解決済み】Android Studioの初回起動。Android SDKアドオンリストにアクセスできない
-
[解決済み】ビューのルートとしてNULLを渡さないようにする(膨張したレイアウトのルート要素でレイアウトパラメータを解決する必要がある)。
-
[解決済み] [Solved] java.lang.RuntimeException: アクティビティーのインスタンス化ができません ComponentInfo
-
[解決済み】Build Tools リビジョン 23.0.1 の検索に失敗しました。
-
[解決済み] エラー - Android リソースのリンクに失敗しました (AAPT2 27.0.3 Daemon #0)
-
[解決済み] Android Fragment no view found for ID?
-
[解決済み] Android: @drawable/picture を drawable に変換するのに失敗しました。