如何使用 MVVM 架构实现 Firebase Google SignIn?

Posted

技术标签:

【中文标题】如何使用 MVVM 架构实现 Firebase Google SignIn?【英文标题】:How to implement Firebase Google SignIn with MVVM architecture? 【发布时间】:2019-10-20 18:46:13 【问题描述】:

我正在构建一个应用程序,但我目前面临一个问题:我按照google guide 在 LoginActivity 中编写了我的 Google/Facebook 登录按钮的所有事件。但是,我不想将业务代码保留在活动中以遵循 MVVM 架构。因此,如何放置 Firebase 方法(需要活动引用和生命周期回调)?

我尝试了一个正在运行的 LoginViewModel,但它引用了 LoginActivity

class LoginViewModel(application: Application) : BaseViewModelContext(application) 

    lateinit var auth: FirebaseAuth
    val Tag: String = LoginViewModel::class.java.simpleName;
    val gso: GoogleSignInOptions
    val googleSignInClient: GoogleSignInClient

    init 
        auth = FirebaseAuth.getInstance()
        gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(application.getString(R.string.default_client_id))
            .build()

        googleSignInClient = GoogleSignIn.getClient(application, gso)
    



    fun activityForResultLogin(requestCode:Int, resultCode: Int, data: Intent?, activity: Activity)
        if(requestCode == Constants.RC_SIGN_IN)
            val task = GoogleSignIn.getSignedInAccountFromIntent(data)
            try 
                // Google Sign In was successful, authenticate with Firebase
                val account = task.getResult(ApiException::class.java)
                firebaseAuthWithGoogle(account!!, activity)
             catch (e: ApiException) 
                // Google Sign In failed, update UI appropriately
                Log.w(Tag, "Google sign in failed", e)
                // ...
            
        
    

    private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount, activity: Activity) 
        Log.d(Tag, "firebaseAuthWithGoogle:" + acct.id!!)

        val credential = GoogleAuthProvider.getCredential(acct.idToken, null)
        auth.signInWithCredential(credential)
            .addOnCompleteListener(activity)  task ->
                if (task.isSuccessful) 
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(Tag, "signInWithCredential:success")
                    val user = auth.currentUser
                    activity.shortToast("SignInSuccess")
                 else 
                    // If sign in fails, display a message to the user.
                    Log.w(Tag, "signInWithCredential:failure", task.exception)
                    activity.shortToast("SignInFailed")
                

            
    

    fun signInGoogle(activity: Activity)
        val signInIntent = googleSignInClient.signInIntent
        activity.startActivityForResult(signInIntent, Constants.RC_SIGN_IN)
    

    fun signOutGoogle(activity: Activity)
        googleSignInClient.signOut().addOnCompleteListener(activity)
            //Update ui
        
    

【问题讨论】:

看看 Paha 实现 GoogleSignIn 的实现:github.com/jojink/android-Kotlin-FirebaseAuth/blob/feature/…希望这会有所帮助。 那个 git 看起来更像 MVP no MVVM 如果您对干净的 Firebase 身份验证感兴趣,可以查看此article。 在 codelab github.com/googlecodelabs/android-kotlin-logingoogle 上查看这个例子 你好@ELTEGANIMOHAMED!谢谢 !这正是我想要的:) 【参考方案1】:

这是我所做的。

创建用户模型:

data class User(
    val uid: String,
    val name: String?,
    val email: String?,
    var isAuthenticated: Boolean = false,
    var isNew: Boolean? = false,
    var isCreated: Boolean = false

) : Serializable

    constructor() : this("","","") 

    


创建 AuthRepository 类:

class AuthRepository 

    private val firebaseAuth: FirebaseAuth = FirebaseAuth.getInstance()
    private val rootRef: FirebaseFirestore = FirebaseFirestore.getInstance()
    private val usersRef: CollectionReference = rootRef.collection(USERS)

    // Sign in using google
    fun firebaseSignInWithGoogle(googleAuthCredential: AuthCredential): MutableLiveData<ResponseState<User>> 
        val authenticatedUserMutableLiveData: MutableLiveData<ResponseState<User>> =
            MutableLiveData()
       
         firebaseAuth.signInWithCredential(googleAuthCredential).addOnCompleteListener  authTask ->
            if (authTask.isSuccessful) 
                var isNewUser = authTask.result?.additionalUserInfo?.isNewUser
                val firebaseUser: FirebaseUser? = firebaseAuth.currentUser
                if (firebaseUser != null) 
                    val uid = firebaseUser.uid
                    val name = firebaseUser.displayName
                    val email = firebaseUser.email
                    val user = User(uid = uid, name = name, email = email)
                    user.isNew = isNewUser
                    authenticatedUserMutableLiveData.value = ResponseState.Success(user)

                


             else 

                authenticatedUserMutableLiveData.value = authTask.exception?.message?.let 
                    ResponseState.Error(it)
                

            


        
        return authenticatedUserMutableLiveData
    


创建 LoginViewModel 类:

class LoginViewModel constructor(private val authRepository: AuthRepository) :
    ViewModel() 

    private var _authenticateUserLiveData: MutableLiveData<ResponseState<User>> = MutableLiveData()
  val authenticateUserLiveData: LiveData<ResponseState<User>> get() = _authenticateUserLiveData

    fun signInWithGoogle(googleAuthCredential: AuthCredential) 
        _authenticateUserLiveData = authRepository.firebaseSignInWithGoogle(googleAuthCredential)
    



这里的ResponseState类如下:

sealed class ResponseState<T>(
    val data: T? = null,
    val message: String? = null
) 


    class Success<T>(data: T) : ResponseState<T>(data)
    class Error<T>(message: String) : ResponseState<T>(message = message)
    class Loading<T> : ResponseState<T>()


在您的活动或片段中,您可以将其用作:

lateinit var googleSignInClient: GoogleSignInClient
private fun initGoogleSignInClient() 
    val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestIdToken(getString(R.string.default_web_client_id))
        .requestEmail()
        .build()

    googleSignInClient = GoogleSignIn.getClient(this, gso)


private fun signInUsingGoolge() 
    val signInGoogleIntent = (activity as MainActivity).googleSignInClient.signInIntent
    startActivityForResult(signInGoogleIntent, RC_SIGN_IN)

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

    if (requestCode == RC_SIGN_IN) 
        val task = GoogleSignIn.getSignedInAccountFromIntent(data)
        try 
            // Google Sign In was successful, authenticate with Firebase
            val account = task.getResult(ApiException::class.java) !!
                if (account != null) 
                    getGoogleAuthCredential(account)
                

         catch (e: ApiException) 
            // Google Sign In failed, update UI appropriately
        
    


private fun getGoogleAuthCredential(account: GoogleSignInAccount) 
    binding.progressBar.visible()
    val googleTokeId = account.idToken
    val googleAuthCredential = GoogleAuthProvider.getCredential(googleTokeId, null)
    signInWithGoogleAuthCredential(googleAuthCredential)


private fun signInWithGoogleAuthCredential(googleAuthCredential: AuthCredential) 

    loginViewModel.signInWithGoogle(googleAuthCredential)
    loginViewModel.authenticateUserLiveData.observe(viewLifecycleOwner, 
        authenticatedUser - >
        when(authenticatedUser) 
            is ResponseState.Error - > 
                authenticatedUser.message ? .let 
                    context ? .toast(it)
                
            
            is ResponseState.Success - > 
                if (authenticatedUser.data != null)
                //update ui
            
            is ResponseState.Loading - > 
                //show progress
            
        
    )

 
      

【讨论】:

以上是关于如何使用 MVVM 架构实现 Firebase Google SignIn?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 应用架构实现 MVVM、网络和蓝牙,如何实现?

Android MVVM 架构应用实现

如何在Android MVVM架构中实现对话框选择选项

如何使用MVVM + Swift4实现注册屏幕

Flutter开发 - 使用GetX框架实现类似MVVM架构

如何在 Room MVVM 架构中实现 Koin 依赖注入