[Android/Kotlin] 구글 Google 계정 로그인 연동을 위한 firebase...

[Android/Kotlin] 구글 Google 계정 로그인 연동을 위한 firebase...

728x90

안녕하세용! 안드로이드 앱에서 Firebase 를 활용하여 Google 로그인 하는 방법 및 소스코드 입니다.

1. Firebase Auth Google 설정 방법

https://eunoia3jy.tistory.com/129

1-1. Firebase 프로젝트 생성 및 앱 추가가 끝났다면 Firebase Console 에서 빌드 > Authentication 클릭

1-2. Sign-in method 탭에서 Google 에서 클릭

1-3. Google 을 사용설정으로 변경하고 프로젝트 지원 이메일 입력 후 저장

2. 소스 코드

LoginActivity.kt

internal class LoginActivity : AppCompatActivity() { companion object { const val TAG = "LoginActivity" } private val viewModel: LoginViewModel = LoginViewModel() private lateinit var binding: ActivityLoginBinding //activity_login.xml 을 바인딩 private lateinit var fetchJob: Job private var tokenId: String? = null //Google Auth 인증에 성공하면 token 값으로 설정된다 /* GoogleSignInOptions */ private val googleSignInOptions: GoogleSignInOptions by lazy { GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.default_web_client_id)) .requestEmail() .build() } /* GoogleSignIn */ private val googleSignIn by lazy { GoogleSignIn.getClient(this, googleSignInOptions) } /* FirebaseAuth */ private val firebaseAuth by lazy { FirebaseAuth.getInstance() } /* Google Auth 로그인 결과 수신 */ private val loginLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> Log.d(TAG, "loginLauncher - result : $result") if (result.resultCode == Activity.RESULT_OK) { val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) try { task.getResult(ApiException::class.java)?.let { account -> Log.d(TAG, "loginLauncher - firebaseAuthWithGoogle : ${account.id}") tokenId = account.idToken viewModel.saveToken( tokenId ?: throw java.lang.Exception() ) //Loading 상태 이후 Login 상태로 변경 } ?: throw Exception() } catch (e: Exception) { e.printStackTrace() handleErrorState() //Error 상태 } } else { handleErrorState() //Error 상태 } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityLoginBinding.inflate(layoutInflater) setContentView(binding.root) //xml 전체를 감싸는 최상단 부모를 root 라는 property 로 제공 fetchJob = viewModel.fetchData(tokenId) initViews() observeData() } /* view 기본 설정 */ private fun initViews() = with(binding) { tokenId?.let { //로그인 된 상태 groupLoginRequired.isGone = true groupLogoutRequired.isVisible = true } ?: kotlin.run { //로그인 안된 상태 groupLoginRequired.isVisible = true groupLogoutRequired.isGone = true } btnLogin.setOnClickListener { //로그인 버튼 클릭 시 val signInIntent: Intent = googleSignIn.signInIntent loginLauncher.launch(signInIntent) //loginLauncher 로 결과 수신하여 처리 } btnLogout.setOnClickListener { //로그아웃 버튼 클릭 시 viewModel.signOut() } } /* viewModel 을 관찰하여 상태 변화에 따라 처리 */ private fun observeData() = viewModel.loginStateLiveData.observe(this) { Log.d(TAG, "observeData() - it : $it") when (it) { is LoginState.UnInitialized -> initViews() is LoginState.Loading -> handleLoadingState() is LoginState.Login -> handleLoginState(it) is LoginState.Success -> handleSuccessState(it) is LoginState.Error -> handleLoadingState() } } /* Loading 상태인 경우 */ private fun handleLoadingState() = with(binding) { progressBar.isVisible = true groupLoginRequired.isGone = true groupLogoutRequired.isGone = true } /* Google Auth Login 상태인 경우 */ private fun handleLoginState(state: LoginState.Login) = with(binding) { progressBar.isVisible = true val credential = GoogleAuthProvider.getCredential(state.idToken, null) firebaseAuth.signInWithCredential(credential) .addOnCompleteListener(this@LoginActivity) { task -> if (task.isSuccessful) { //Login 성공 viewModel.setUserInfo(firebaseAuth.currentUser) //Login 상태 이후 Success 상태로 변경, 정보 설정 } else { //Login 실패 viewModel.setUserInfo(null) } } } /* Google Auth Login Success 상태인 경우 */ private fun handleSuccessState(state: LoginState.Success) = with(binding) { progressBar.isGone = true when (state) { is LoginState.Success.Registered -> { //Google Auth 등록된 상태 handleRegisteredState(state) //Success.Registered 상태로 변경 } is LoginState.Success.NotRegistered -> { //Google Auth 미등록된 상태 Toast.makeText(this@LoginActivity, "NotRegistered", Toast.LENGTH_SHORT).show() groupLoginRequired.isVisible = true groupLogoutRequired.isGone = true } } } /* Google Auth Login Registered 상태인 경우 */ private fun handleRegisteredState(state: LoginState.Success.Registered) = with(binding) { groupLogoutRequired.isVisible = true groupLoginRequired.isGone = true Glide.with(this@LoginActivity) .load(state.profileImgeUri.toString()) .transition( DrawableTransitionOptions.withCrossFade( DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build() ) ) .diskCacheStrategy(DiskCacheStrategy.ALL) .apply { transforms(CenterCrop(), RoundedCorners(60f.fromDpToPx())) } .into(ivProfile) tvUsername.text = state.userName } /* Error 상태인 경우 */ private fun handleErrorState() = with(binding) { Toast.makeText(this@LoginActivity, "Error State", Toast.LENGTH_SHORT).show() } }

activity_login.xml

LoginViewModel.kt

internal class LoginViewModel() : ViewModel() { private var _loginStateLiveData = MutableLiveData(LoginState.UnInitialized) val loginStateLiveData: LiveData = _loginStateLiveData fun fetchData(tokenId: String?): Job = viewModelScope.launch { setState(LoginState.Loading) tokenId?.let { setState( LoginState.Login(it) ) } ?: kotlin.run { setState( LoginState.Success.NotRegistered ) } } /* 로그인 성공 result 받았을 떄 호출 */ fun saveToken(idToken: String) = viewModelScope.launch { withContext(Dispatchers.IO) { fetchData(idToken) } } /* 로그인 성공 후 정보 설정 */ fun setUserInfo(firebaseUser: FirebaseUser?) = viewModelScope.launch { firebaseUser?.let { user -> setState( LoginState.Success.Registered( user.displayName ?: "익명", user.photoUrl!!, ) ) } ?: kotlin.run { setState(LoginState.Success.NotRegistered) } } /* 로그아웃 버튼 클릭 시 호출 */ fun signOut() = viewModelScope.launch { fetchData(null) } private fun setState(state: LoginState) { _loginStateLiveData.postValue(state) } }

LoginState.kt

sealed class LoginState { object UnInitialized : LoginState() object Loading : LoginState() data class Login( val idToken: String ) : LoginState() sealed class Success : LoginState() { data class Registered( //Google Auth 등록된 상태 val userName: String, val profileImgeUri: Uri, ) : Success() object NotRegistered : Success() //Google Auth 미등록된 상태 } object Error : LoginState() }

결과 화면

로그인 전 화면 / 로그인 후 화면

감사합니다!

728x90

from http://eunoia3jy.tistory.com/133 by ccl(A) rewrite - 2021-09-22 10:01:13