From eee3ffd408490a080fb93031966a05484a2ffdbf Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Mon, 12 Jun 2023 11:42:18 +0900 Subject: [PATCH 1/9] =?UTF-8?q?Google,=20Kakao=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EA=B4=80=EB=A0=A8=20module,=20dependency=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index ebde7f8..12e2727 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,8 @@ plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' id 'androidx.navigation.safeargs.kotlin' + id 'com.google.gms.google-services' + id 'com.google.firebase.crashlytics' } android { @@ -99,4 +101,15 @@ dependencies { // logging implementation "com.squareup.okhttp3:logging-interceptor:4.9.0" + // 구글 로그인 모듈 + implementation 'com.google.android.gms:play-services-auth:20.5.0' + + implementation platform('com.google.firebase:firebase-bom:32.1.0') + implementation 'com.google.firebase:firebase-analytics-ktx' + implementation 'com.google.firebase:firebase-crashlytics-ktx' + implementation 'com.google.firebase:firebase-messaging-ktx' + implementation 'com.google.firebase:firebase-auth-ktx' + + // 카카오 로그인 모듈 + implementation "com.kakao.sdk:v2-user:2.14.0" } \ No newline at end of file From 3470194f795e64aee529092a8842fc53f27dc911 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Mon, 12 Jun 2023 11:42:24 +0900 Subject: [PATCH 2/9] =?UTF-8?q?Google,=20Kakao=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EA=B4=80=EB=A0=A8=20module,=20dependency=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 41d9ba4..9fc864e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,10 +3,13 @@ buildscript { repositories { google() mavenCentral() + maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/'} } dependencies { classpath 'com.android.tools.build:gradle:7.3.1' classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3" + classpath 'com.google.gms:google-services:4.3.15' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.5' } } plugins { @@ -14,4 +17,5 @@ plugins { id 'com.android.library' version '7.3.1' apply false id 'org.jetbrains.kotlin.android' version '1.8.20' apply false id 'com.google.dagger.hilt.android' version '2.45' apply false + id 'com.google.gms.google-services' version '4.3.8' apply false } \ No newline at end of file From 7ead71fe979ccd3d4339243312136029508e46c0 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Mon, 12 Jun 2023 11:43:00 +0900 Subject: [PATCH 3/9] =?UTF-8?q?Kakao=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20module=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- settings.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.gradle b/settings.gradle index 215bb73..7ea6683 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/'} } } rootProject.name = "DiningCoach-Android" From 86052aa986acd5c85efd57c7d9b93b84d3b83ae6 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Mon, 12 Jun 2023 11:43:39 +0900 Subject: [PATCH 4/9] =?UTF-8?q?Kakao=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20meta-data=20=EC=99=80=20activity=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f996e05..84040ec 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,6 +56,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file From a80ffccd3673cbbf4e7be55710e4d0bae9a6211f Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Mon, 12 Jun 2023 11:44:16 +0900 Subject: [PATCH 5/9] =?UTF-8?q?Kakao=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=98=A4=EB=A5=98=20string=20values=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/values/strings.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 635e1d5..04b0ada 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,6 +16,24 @@ 이메일을 입력해 주세요 로그인에 문제가 있으신가요? + 토큰 정보 보기 실패 + 토큰 정보 보기 성공 + + 접근이 거부됨(동의 취소) + 유효하지 않은 앱 + + 인증 수단이 유효하지 않아 인증할 수 없는 상태 + 요청 파라미터 오류 + 유효하지 않은 scope ID + 설정이 올바르지 않음(android key hash error)" + 서버 내부 에러 + 앱이 요청 권한이 없음 + 기타 에러 + + 로그인에 성공하였습니다. + + 877625a3bd221ae6e830c9a1efcc0f06 + kakao877625a3bd221ae6e830c9a1efcc0f06 Dining Coach Alarm 설명 문구 From 45a3fa737db1e31896a73827075cb09eb9bd40b0 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Tue, 13 Jun 2023 21:22:58 +0900 Subject: [PATCH 6/9] =?UTF-8?q?MainActivity=20=EC=9D=98=20getIntent=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/dining/coach/ui/main/MainActivity.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/dining/coach/ui/main/MainActivity.kt b/app/src/main/java/com/dining/coach/ui/main/MainActivity.kt index a8fd8ca..1584ea5 100644 --- a/app/src/main/java/com/dining/coach/ui/main/MainActivity.kt +++ b/app/src/main/java/com/dining/coach/ui/main/MainActivity.kt @@ -1,5 +1,7 @@ package com.dining.coach.ui.main +import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.activity.viewModels import com.dining.coach.R @@ -17,4 +19,9 @@ class MainActivity : BaseActivity(R.layout.activity_main) { override fun createActivity(): BaseViewModel { return viewModel } + + companion object { + fun getIntent(context: Context) = + Intent(context, MainActivity::class.java) + } } \ No newline at end of file From 000bf51b327eadbf457494566c8f2109c2457950 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Tue, 13 Jun 2023 21:23:44 +0900 Subject: [PATCH 7/9] =?UTF-8?q?Kakao=20=EB=A1=9C=EA=B7=B8=EC=9D=B8,=20Goog?= =?UTF-8?q?le=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dining/coach/ui/login/LoginActivity.kt | 282 +++++++++++++++++- 1 file changed, 280 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/dining/coach/ui/login/LoginActivity.kt b/app/src/main/java/com/dining/coach/ui/login/LoginActivity.kt index 6c442a9..ce3ab1a 100644 --- a/app/src/main/java/com/dining/coach/ui/login/LoginActivity.kt +++ b/app/src/main/java/com/dining/coach/ui/login/LoginActivity.kt @@ -1,19 +1,297 @@ package com.dining.coach.ui.login +import android.content.Intent +import android.util.Log +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import com.dining.coach.R import com.dining.coach.base.BaseActivity import com.dining.coach.base.BaseViewModel import com.dining.coach.databinding.ActivityLoginBinding -import com.dining.coach.ui.splash.SplashViewModel +import com.dining.coach.ui.main.MainActivity +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInAccount +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.tasks.Task +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.GoogleAuthProvider +import com.kakao.sdk.auth.AuthApiClient +import com.kakao.sdk.auth.model.OAuthToken +import com.kakao.sdk.common.KakaoSdk +import com.kakao.sdk.common.model.AuthErrorCause +import com.kakao.sdk.common.model.ClientError +import com.kakao.sdk.common.model.ClientErrorCause +import com.kakao.sdk.common.model.KakaoSdkError +import com.kakao.sdk.common.util.Utility +import com.kakao.sdk.user.UserApiClient import dagger.hilt.android.AndroidEntryPoint + @AndroidEntryPoint -class LoginActivity: BaseActivity(R.layout.activity_login) { +class LoginActivity : BaseActivity(R.layout.activity_login) { + private lateinit var googleSignInClient: GoogleSignInClient + private val auth = FirebaseAuth.getInstance() + private val user = auth.currentUser + private val viewModel: LoginViewModel by viewModels() override fun createActivity(): BaseViewModel { + initKakaoSignInSetting() + initGoogleSignInSetting() + setOnClickListeners() + bind.vm = viewModel return viewModel } + + private fun initKakaoSignInSetting() { + val keyHash = Utility.getKeyHash(this) + Log.e("Key", "keyHash: $keyHash") + /** Kakao SDK init */ + KakaoSdk.init(this, this.getString(R.string.kakao_app_key)) + } + + private fun initGoogleSignInSetting() { + // 앱에 필요한 사용자 데이터를 요청하도록 로그인 옵션을 설정. + // 유저 아이디와 기본 프로필 정보 요청 + val signIn = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(getString(R.string.default_web_client_id)) + .requestEmail() + .build() + + googleSignInClient = GoogleSignIn.getClient(this, signIn) + } + + private fun setOnClickListeners() { + bind.btnKakao.setOnClickListener { + signInWithKakao() + } + + bind.btnGoogle.setOnClickListener { + signInWithGoogle() + } + } + + override fun onResume() { + super.onResume() +// autoSignInWithKakao() +// autoSignInWithGoogle() + } + + + /* + * 카카오 소셜 로그인 + */ + + private fun signInWithKakao() { + // 카카오 계정으로 로그인 공통 callback 구성 + // 카카오톡으로 로그인 할 수 없어 카카오 계정으로 로그인할 경우 사용됨 + val callback: (OAuthToken?, Throwable?) -> Unit = { tokenInfo, error -> + if (error != null) { + Log.e("signInWithKakao - 1", "카카오 계정으로 로그인 실패", error) + when { + error.toString() == AuthErrorCause.AccessDenied.toString() -> + Toast.makeText(this, getString(R.string.access_denied), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidClient.toString() -> + Toast.makeText(this, getString(R.string.invalid_client), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidGrant.toString() -> + Toast.makeText(this, getString(R.string.invalid_grant), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidRequest.toString() -> + Toast.makeText(this, getString(R.string.invalid_request), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidScope.toString() -> + Toast.makeText(this, getString(R.string.invalid_scope), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Misconfigured.toString() -> + Toast.makeText(this, getString(R.string.mis_configured), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.ServerError.toString() -> + Toast.makeText(this, getString(R.string.server_error), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Unauthorized.toString() -> + Toast.makeText(this, getString(R.string.unauthorized), Toast.LENGTH_SHORT).show() + else -> + Toast.makeText(this, getString(R.string.etc_error), Toast.LENGTH_SHORT).show() + } + } + else if (tokenInfo != null) { + onSignInSuccess() + Log.i("signInWithKakao - 2", "카카오 계정으로 로그인 성공 ${tokenInfo.accessToken}") + } + } + + // 로그인을 통해 발급 받은 토큰이 있는지 확인 +// checkAuthenticatedToken(callback) + + // 해당 기기에 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오 계정으로 로그인 + if (UserApiClient.instance.isKakaoTalkLoginAvailable(this)) { + UserApiClient.instance.loginWithKakaoTalk(this) { tokenInfo, error -> + if (error != null) { + Log.e("signInWithKakao - 3", "카카오톡으로 로그인 실패", error) + + // 사용자가 카카오톡 설치 후 디바이스 권한 요청 화면에서 로그인을 취소한 경우, + // 의도적인 로그인 취소로 보고 카카오 계정으로 로그인 시도 없이 로그인 취소로 처리 (예: 뒤로 가기) + if (error is ClientError && error.reason == ClientErrorCause.Cancelled) { + return@loginWithKakaoTalk + } + + // 카카오톡에 연결된 카카오 계정이 없는 경우, 카카오 계정으로 로그인 시도 + UserApiClient.instance.loginWithKakaoAccount(this, callback = callback) + } else if (tokenInfo != null) { + onSignInSuccess() + Log.i("signInWithKakao - 4", "카카오톡으로 로그인 성공 : ${tokenInfo.accessToken}") + } + } + } else { + UserApiClient.instance.loginWithKakaoAccount(this, callback = callback) + } + } + + private fun checkAuthenticatedToken(callback: (OAuthToken?, Throwable?) -> Unit) { + if (AuthApiClient.instance.hasToken()) { // hasToken()의 결과가 true라도 현재 사용자가 로그인 상태임을 보장하지 + UserApiClient.instance.accessTokenInfo { tokenInfo, error -> + if (error != null) { + if (error is KakaoSdkError && error.isInvalidTokenError()) { + // 로그인 필요 + UserApiClient.instance.loginWithKakaoAccount(this, callback = callback) + } else { + // 기타 에러 + Log.e("checkAuthenticatedToken - 1", "카카오 로그인 실패", error) + } + } else if (tokenInfo != null) { + Log.i( + "checkAuthenticatedToken - 2", "토큰 정보 보기 성공" + + "\n회원번호: ${tokenInfo.id}" + + "\n만료시간: ${tokenInfo.expiresIn} 초" + ) + } else { + // 토큰 유효성 체크 성공(필요 시 토큰 갱신됨) + } + } + } else { + //로그인 필요 + UserApiClient.instance.loginWithKakaoAccount(this, callback = callback) + } + } + + private fun autoSignInWithKakao() { + val callback: (OAuthToken?, Throwable?) -> Unit = { tokenInfo, error -> + if (error != null) { + Log.e("signInKakao - 1", "카카오 계정으로 로그인 실패", error) + when { + error.toString() == AuthErrorCause.AccessDenied.toString() -> + Toast.makeText(this, getString(R.string.access_denied), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidClient.toString() -> + Toast.makeText(this, getString(R.string.invalid_client), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidGrant.toString() -> + Toast.makeText(this, getString(R.string.invalid_grant), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidRequest.toString() -> + Toast.makeText(this, getString(R.string.invalid_request), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidScope.toString() -> + Toast.makeText(this, getString(R.string.invalid_scope), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Misconfigured.toString() -> + Toast.makeText(this, getString(R.string.mis_configured), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.ServerError.toString() -> + Toast.makeText(this, getString(R.string.server_error), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Unauthorized.toString() -> + Toast.makeText(this, getString(R.string.unauthorized), Toast.LENGTH_SHORT).show() + else -> + Toast.makeText(this, getString(R.string.etc_error), Toast.LENGTH_SHORT).show() + } + } + else if (tokenInfo != null) { + onSignInSuccess() + Log.i("autoSignInWithKakao", "카카오 계정으로 자동 로그인 성공 ${tokenInfo.accessToken}") + } + } + + // 사용자 정보 요청 (기본) + UserApiClient.instance.me { user, error -> + // 에러가 존재할 경우(로그인 정보 없음) -> 로그인 시도 + if (error != null) { + Log.e("autoSignInWithKakao", "autoSignInKakao 사용자 정보 요청 실패", error) + UserApiClient.instance.run { + if(isKakaoTalkLoginAvailable(this@LoginActivity)) + loginWithKakaoTalk(this@LoginActivity, callback = callback) + else + loginWithKakaoAccount(this@LoginActivity, callback = callback) + } + } + else if (user != null) { // 유저 정보가 존재할 경우 -> kakaoId로 개인 API 서버에서 유저 정보 획득 + Log.i("autoSignInWithKakao", "autoSignInKakao 사용자 정보 요청 성공" + + "\n회원번호: ${user.id}" + + "\n이메일: ${user.kakaoAccount?.email}" + + "\n닉네임: ${user.kakaoAccount?.profile?.nickname}" + + "\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}") + onSignInSuccess() + } + } + } + + + /* + * 구글 소셜 로그인 + */ + + private fun signInWithGoogle() { + val signIntent = googleSignInClient.signInIntent + googleSignInResultLauncher.launch(signIntent) + } + + private val googleSignInResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + Log.e(javaClass.simpleName, "result.resultCode : ${result.resultCode}!!!") + Log.e(javaClass.simpleName, "RESULT_OK : $RESULT_OK") + + if (result.resultCode == RESULT_OK) { + val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) + Log.e(javaClass.simpleName, "result.data : ${result.data}") + Log.e(javaClass.simpleName, "task : $task") + handleGoogleSignInResult(task) + } else { + Log.e(javaClass.simpleName, "googleSignInResultLauncher: error") + } + } + + private fun handleGoogleSignInResult(task: Task) { + Log.e(javaClass.simpleName, "handleGoogleSignInResult : 들어옴!!!") + Log.e(javaClass.simpleName, "task : $task!!!") + + if (task.isSuccessful) { + val account = task.result + val email = account?.email + val familyName = account?.familyName + if (account != null && email != null && familyName != null) { + firebaseUserAuthWithGoogle(account) + } + } + } + + private fun firebaseUserAuthWithGoogle(account: GoogleSignInAccount) { + Log.e(javaClass.simpleName, "firebaseUserAuthWithGoogle : 들어옴!!!") + val credential = GoogleAuthProvider.getCredential(account.idToken, null) + auth.signInWithCredential(credential).addOnCompleteListener { + if (it.isSuccessful) { + onSignInSuccess() + Log.d(javaClass.simpleName, "firebaseUserAuthWithGoogle : 성공!!!") + } else { + Toast.makeText(this, it.exception.toString(), Toast.LENGTH_SHORT).show() + } + } + } + + private fun autoSignInWithGoogle() { + user?.getIdToken(true) + ?.addOnCompleteListener { task -> + if (task.isSuccessful) { + val idToken = task.result.token + Log.d("autoSignInWithGoogle", "idToken: $idToken") + onSignInSuccess() + } else { + task.exception?.printStackTrace() + } + } + } + + private fun onSignInSuccess() { + val intent = MainActivity.getIntent(this) + startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) + } } \ No newline at end of file From f27593cfd6cd2d079317350c043a5eda2f67b037 Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Tue, 13 Jun 2023 21:24:15 +0900 Subject: [PATCH 8/9] =?UTF-8?q?Kakao=20=EC=9E=90=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8,=20Google=20=EC=9E=90=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dining/coach/ui/splash/SplashActivity.kt | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/app/src/main/java/com/dining/coach/ui/splash/SplashActivity.kt b/app/src/main/java/com/dining/coach/ui/splash/SplashActivity.kt index 3fd641a..db75ddc 100644 --- a/app/src/main/java/com/dining/coach/ui/splash/SplashActivity.kt +++ b/app/src/main/java/com/dining/coach/ui/splash/SplashActivity.kt @@ -1,6 +1,9 @@ package com.dining.coach.ui.splash import android.annotation.SuppressLint +import android.content.Intent +import android.util.Log +import android.widget.Toast import androidx.activity.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver @@ -12,6 +15,15 @@ import com.dining.coach.base.BaseViewModel import com.dining.coach.databinding.ActivitySplashBinding import com.dining.coach.ui.login.LoginActivity import com.dining.coach.ui.main.MainActivity +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.firebase.auth.FirebaseAuth +import com.kakao.sdk.auth.model.OAuthToken +import com.kakao.sdk.common.KakaoSdk +import com.kakao.sdk.common.model.AuthErrorCause +import com.kakao.sdk.common.util.Utility +import com.kakao.sdk.user.UserApiClient import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart @@ -23,13 +35,25 @@ import kotlinx.coroutines.launch @SuppressLint("CustomSplashScreen") @AndroidEntryPoint class SplashActivity: BaseActivity(R.layout.activity_splash) { + private lateinit var googleSignInClient: GoogleSignInClient + private val auth = FirebaseAuth.getInstance() + private val user = auth.currentUser private val viewModel: SplashViewModel by viewModels() override fun createActivity(): BaseViewModel { + initKakaoSignInSetting() + initGoogleSignInSetting() return viewModel } + override fun onStart() { + super.onStart() + +// autoSignInWithKakao() // 카카오 자동 로그인 +// autoSignInWithGoogle() // 구글 자동 로그인 + } + override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) @@ -51,4 +75,95 @@ class SplashActivity: BaseActivity(R.layout.activity_spla } } } + + private fun initKakaoSignInSetting() { + val keyHash = Utility.getKeyHash(this) + Log.e("Key", "keyHash: $keyHash") + /** Kakao SDK init */ + KakaoSdk.init(this, this.getString(R.string.kakao_app_key)) + } + + private fun initGoogleSignInSetting() { + // 앱에 필요한 사용자 데이터를 요청하도록 로그인 옵션을 설정. + // 유저 아이디와 기본 프로필 정보 요청 + val signIn = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(getString(R.string.default_web_client_id)) + .requestEmail() + .build() + + googleSignInClient = GoogleSignIn.getClient(this, signIn) + } + + + private fun autoSignInWithKakao() { + val callback: (OAuthToken?, Throwable?) -> Unit = { tokenInfo, error -> + if (error != null) { + Log.e("signInKakao - 1", "카카오 계정으로 로그인 실패", error) + when { + error.toString() == AuthErrorCause.AccessDenied.toString() -> + Toast.makeText(this, getString(R.string.access_denied), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidClient.toString() -> + Toast.makeText(this, getString(R.string.invalid_client), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidGrant.toString() -> + Toast.makeText(this, getString(R.string.invalid_grant), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidRequest.toString() -> + Toast.makeText(this, getString(R.string.invalid_request), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.InvalidScope.toString() -> + Toast.makeText(this, getString(R.string.invalid_scope), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Misconfigured.toString() -> + Toast.makeText(this, getString(R.string.mis_configured), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.ServerError.toString() -> + Toast.makeText(this, getString(R.string.server_error), Toast.LENGTH_SHORT).show() + error.toString() == AuthErrorCause.Unauthorized.toString() -> + Toast.makeText(this, getString(R.string.unauthorized), Toast.LENGTH_SHORT).show() + else -> + Toast.makeText(this, getString(R.string.etc_error), Toast.LENGTH_SHORT).show() + } + } + else if (tokenInfo != null) { + onSignInSuccess() + Log.i("autoSignInWithKakao", "카카오 계정으로 자동 로그인 성공 ${tokenInfo.accessToken}") + } + } + + // 사용자 정보 요청 (기본) + UserApiClient.instance.me { user, error -> + // 에러가 존재할 경우(로그인 정보 없음) -> 로그인 시도 + if (error != null) { + Log.e("autoSignInWithKakao", "autoSignInKakao 사용자 정보 요청 실패", error) + UserApiClient.instance.run { + if(isKakaoTalkLoginAvailable(this@SplashActivity)) + loginWithKakaoTalk(this@SplashActivity, callback = callback) + else + loginWithKakaoAccount(this@SplashActivity, callback = callback) + } + } + else if (user != null) { // 유저 정보가 존재할 경우 -> kakaoId로 개인 API 서버에서 유저 정보 획득 + Log.i("autoSignInWithKakao", "autoSignInKakao 사용자 정보 요청 성공" + + "\n회원번호: ${user.id}" + + "\n이메일: ${user.kakaoAccount?.email}" + + "\n닉네임: ${user.kakaoAccount?.profile?.nickname}" + + "\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}") + onSignInSuccess() + } + } + } + + private fun autoSignInWithGoogle() { + user?.getIdToken(true) + ?.addOnCompleteListener { task -> + if (task.isSuccessful) { + val idToken = task.result.token + Log.d("autoSignInWithGoogle", "idToken: $idToken") + onSignInSuccess() + } else { + task.exception?.printStackTrace() + } + } + } + + private fun onSignInSuccess() { + val intent = MainActivity.getIntent(this) + startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) + } } \ No newline at end of file From 7e72fa3027db16ed38db3b9b3351df1e6ada6f2d Mon Sep 17 00:00:00 2001 From: thsamajiki Date: Tue, 13 Jun 2023 21:24:47 +0900 Subject: [PATCH 9/9] =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B2=84=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B9=B4=EC=B9=B4=EC=98=A4/=EA=B5=AC=EA=B8=80=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20=EB=A7=88?= =?UTF-8?q?=EC=A7=84=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/activity_login.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index a61a737..f678d4c 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -192,17 +192,18 @@ android:id="@+id/btn_kakao" android:layout_width="@dimen/login_button_round_size" android:layout_height="@dimen/login_button_round_size" - android:layout_marginEnd="16dp" + android:layout_marginEnd="8dp" android:src="@drawable/ic_kakao_round"/> - + + + +