Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ android {
}

dependencies {
implementation(projects.core.domain)
implementation(libs.androidx.work.runtime.ktx)
implementation(libs.kakao.sdk.auth)
implementation(libs.kakao.sdk.user)

// BiometricCryptoGate 가 BiometricPrompt.CryptoObject 를 공개 시그니처로 돌려주므로
// 소비 모듈의 컴파일 클래스패스에도 올라가야 한다 — implementation 이면 반환 타입을 못 본다.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.afternote.feature.setting.presentation.account.social
package com.afternote.core.common.auth

import android.app.Activity
import com.afternote.core.domain.error.CoreAuthFailure
Expand All @@ -9,8 +9,22 @@ import com.kakao.sdk.user.UserApiClient
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

suspend fun requestKakaoAccessToken(activity: Activity): Result<String> =
/**
* 카카오 SDK로부터 OAuth 액세스 토큰을 획득한다.
*
* 플랫폼 SDK가 [Activity] 컨텍스트를 요구하므로 이 함수는 UI 레이어(화면)에서 호출한다.
* Data 레이어(Repository)에는 획득한 액세스 토큰 문자열만 전달되어,
* Data 레이어가 UI 컴포넌트(Activity)에 의존하지 않도록 한다.
* 카카오 로그인(온보딩)과 카카오 계정 연결(설정)이 같은 흐름을 쓰므로 feature 가 아닌 core 에 한 벌을 둔다 (#2194).
*
* 디바이스에 카카오톡이 설치된 경우 앱 로그인을, 그 외에는 웹 계정 로그인을 수행하며,
* 앱 로그인이 비정상 종료된 경우에는 웹 계정 로그인으로 폴백한다.
* 사용자가 로그인을 취소하면 폴백 없이 [CoreAuthFailure.UserCancelledAuth] 로 실패한다.
* 콜백 기반 SDK API를 [suspendCancellableCoroutine]으로 감싸 코루틴 흐름으로 변환한다.
*/
public suspend fun requestKakaoAccessToken(activity: Activity): Result<String> =
suspendCancellableCoroutine { continuation ->
// 공통 콜백: 카카오톡 앱 로그인·웹 계정 로그인 결과를 모두 처리한다.
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (continuation.isActive) {
when {
Expand All @@ -36,20 +50,24 @@ suspend fun requestKakaoAccessToken(activity: Activity): Result<String> =
}

if (UserApiClient.instance.isKakaoTalkLoginAvailable(activity)) {
// 카카오톡 앱이 설치된 경우: 앱 로그인 시도
UserApiClient.instance.loginWithKakaoTalk(activity) { token, error ->
if (error != null) {
// 사용자가 의도적으로 취소한 경우에는 폴백 없이 즉시 실패 처리
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
if (continuation.isActive) {
continuation.resume(Result.failure(CoreAuthFailure.UserCancelledAuth()))
}
return@loginWithKakaoTalk
}
// 그 외 에러(네트워크·앱 오류 등)는 웹 계정 로그인으로 폴백
UserApiClient.instance.loginWithKakaoAccount(activity, callback = callback)
} else {
callback(token, null)
}
}
} else {
// 카카오톡 앱이 없는 경우: 곧바로 웹 계정 로그인
UserApiClient.instance.loginWithKakaoAccount(activity, callback = callback)
}
}
2 changes: 0 additions & 2 deletions feature/setting/presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ dependencies {
implementation(projects.core.ui)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.androidx.compose.runtime)
implementation(libs.kakao.sdk.auth)
implementation(libs.kakao.sdk.user)
implementation(libs.androidx.biometric)
implementation(libs.androidx.credentials)
implementation(libs.androidx.credentials.play.services.auth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import androidx.compose.ui.res.stringResource
import androidx.credentials.CredentialManager
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.afternote.core.common.auth.requestKakaoAccessToken
import com.afternote.core.domain.error.CoreAuthFailure
import com.afternote.core.ui.findActivity
import com.afternote.feature.setting.presentation.BuildConfig
import com.afternote.feature.setting.presentation.R
import com.afternote.feature.setting.presentation.account.social.KakaoAuthResult
import com.afternote.feature.setting.presentation.account.social.requestGoogleIdToken
import com.afternote.feature.setting.presentation.account.social.requestKakaoAccessToken
import com.afternote.feature.setting.presentation.account.social.toKakaoAuthResult

@Composable
Expand Down
Loading