diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4a074d97a..93facf65f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -23,6 +23,14 @@ android {
vectorDrawables {
useSupportLibrary = true
}
+
+ buildConfigField(
+ "String",
+ "NATIVE_APP_KEY",
+ gradleLocalProperties(rootDir, providers).getProperty("native.app.key"),
+ )
+ manifestPlaceholders["NATIVE_APP_KEY"] =
+ gradleLocalProperties(rootDir, providers).getProperty("nativeAppKey")
}
buildTypes {
@@ -104,4 +112,8 @@ dependencies {
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
+
+ // KakaoDependencies
+ implementation(libs.kakao.user)
+
}
diff --git a/app/src/main/java/com/terning/point/MyApp.kt b/app/src/main/java/com/terning/point/MyApp.kt
index 98ac3bc11..2d991562c 100644
--- a/app/src/main/java/com/terning/point/MyApp.kt
+++ b/app/src/main/java/com/terning/point/MyApp.kt
@@ -2,6 +2,7 @@ package com.terning.point
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
+import com.kakao.sdk.common.KakaoSdk
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber
@@ -13,6 +14,7 @@ class MyApp : Application() {
initTimber()
setDayMode()
+ initKakoSdk()
}
private fun initTimber() {
@@ -22,4 +24,8 @@ class MyApp : Application() {
private fun setDayMode() {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
+
+ private fun initKakoSdk() {
+ KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/com/terning/core/extension/ContextExt.kt b/core/src/main/java/com/terning/core/extension/ContextExt.kt
index 7deeaaec9..370fb9f06 100644
--- a/core/src/main/java/com/terning/core/extension/ContextExt.kt
+++ b/core/src/main/java/com/terning/core/extension/ContextExt.kt
@@ -1,9 +1,6 @@
package com.terning.core.extension
-import android.app.Activity
import android.content.Context
-import android.view.View
-import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.annotation.StringRes
diff --git a/feature/build.gradle.kts b/feature/build.gradle.kts
index 56209c2ce..d76df3c05 100644
--- a/feature/build.gradle.kts
+++ b/feature/build.gradle.kts
@@ -91,4 +91,7 @@ dependencies {
implementation(libs.ossLicense)
implementation(libs.lottie)
+ // KakaoDependencies
+ implementation(libs.kakao.user)
+
}
\ No newline at end of file
diff --git a/feature/src/main/AndroidManifest.xml b/feature/src/main/AndroidManifest.xml
index f2df3a230..1e31d319a 100644
--- a/feature/src/main/AndroidManifest.xml
+++ b/feature/src/main/AndroidManifest.xml
@@ -14,5 +14,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt
index a885ac342..472557036 100644
--- a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt
+++ b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt
@@ -10,9 +10,9 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
import com.terning.feature.calendar.navigation.navigateCalendar
-import com.terning.feature.home.navigation.Home
import com.terning.feature.home.navigation.navigateHome
import com.terning.feature.mypage.navigation.navigateMyPage
+import com.terning.feature.onboarding.signin.navigation.SignIn
import com.terning.feature.search.navigation.navigateSearch
class MainNavigator(
@@ -22,7 +22,7 @@ class MainNavigator(
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination
- val startDestination = Home
+ val startDestination = SignIn
val currentTab: MainTab?
@Composable get() = MainTab.find { tab ->
diff --git a/feature/src/main/java/com/terning/feature/main/MainScreen.kt b/feature/src/main/java/com/terning/feature/main/MainScreen.kt
index 257bf2e23..4e3e13d6f 100644
--- a/feature/src/main/java/com/terning/feature/main/MainScreen.kt
+++ b/feature/src/main/java/com/terning/feature/main/MainScreen.kt
@@ -7,13 +7,10 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
-import androidx.compose.material3.LocalAbsoluteTonalElevation
-import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
-import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
@@ -27,6 +24,8 @@ import com.terning.core.designsystem.theme.White
import com.terning.feature.calendar.navigation.calendarNavGraph
import com.terning.feature.home.navigation.homeNavGraph
import com.terning.feature.mypage.navigation.myPageNavGraph
+import com.terning.feature.onboarding.signin.navigation.signInNavGraph
+import com.terning.feature.onboarding.signup.navigation.signUpNavGraph
import com.terning.feature.search.navigation.searchNavGraph
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
@@ -58,6 +57,8 @@ fun MainScreen(
calendarNavGraph()
searchNavGraph()
myPageNavGraph()
+ signInNavGraph(navHostController = navigator.navController)
+ signUpNavGraph()
}
}
}
@@ -108,7 +109,6 @@ private fun MainBottomBar(
}
}
-
private object NoRippleInteractionSource : MutableInteractionSource {
override val interactions: Flow = emptyFlow()
diff --git a/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt b/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt
index f72da0835..2302237e4 100644
--- a/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt
+++ b/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt
@@ -26,7 +26,7 @@ fun MyPageRoute(
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
- val state by viewModel.state.collectAsStateWithLifecycle(lifecycleOwner = LocalLifecycleOwner.current)
+ val state by viewModel.state.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)
LaunchedEffect(key1 = true) {
viewModel.getFriendsInfo(2)
diff --git a/feature/src/main/java/com/terning/feature/onboarding/filtering/FilteringRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/filtering/FilteringRoute.kt
new file mode 100644
index 000000000..bf1e1ec23
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/filtering/FilteringRoute.kt
@@ -0,0 +1,9 @@
+package com.terning.feature.onboarding.filtering
+
+import androidx.compose.runtime.Composable
+import com.terning.feature.onboarding.filtering.navigation.FilteringNavigation
+
+@Composable
+fun FilteringRoute(){
+
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/filtering/navigation/FilteringNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/filtering/navigation/FilteringNavigation.kt
new file mode 100644
index 000000000..6dcc12e7b
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/filtering/navigation/FilteringNavigation.kt
@@ -0,0 +1,4 @@
+package com.terning.feature.onboarding.filtering.navigation
+
+class FilteringNavigation {
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt
new file mode 100644
index 000000000..707a13a21
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt
@@ -0,0 +1,83 @@
+package com.terning.feature.onboarding.signin
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.LocalLifecycleOwner
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.flowWithLifecycle
+import androidx.navigation.NavHostController
+import com.terning.core.designsystem.theme.TerningTheme
+import com.terning.core.extension.toast
+import com.terning.feature.R
+import com.terning.feature.home.navigation.navigateHome
+import com.terning.feature.onboarding.signin.component.KakaoButton
+
+@Composable
+fun SignInRoute(
+ viewModel: SignInViewModel = hiltViewModel(),
+ navController: NavHostController,
+) {
+ val context = LocalContext.current
+ val lifecycleOwner = LocalLifecycleOwner.current
+ val signInState by viewModel.signInState.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)
+
+ LaunchedEffect(viewModel.signInSideEffects, lifecycleOwner) {
+ viewModel.signInSideEffects.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle)
+ .collect { sideEffect ->
+ when (sideEffect) {
+ is SignInSideEffect.ShowToast -> context.toast(sideEffect.message)
+ is SignInSideEffect.NavigateToHome -> navController.navigateHome()
+ }
+ }
+ }
+
+ SignInScreen(
+ onSignInClick = { viewModel.startKakaoLogIn(context) }
+ )
+}
+
+@Composable
+fun SignInScreen(
+ modifier: Modifier = Modifier,
+ onSignInClick: () -> Unit = {}
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.img_terning_point),
+ contentDescription = null,
+ modifier = Modifier
+ .size(500.dp),
+ )
+ KakaoButton(
+ title = stringResource(id = R.string.sign_in_kakao_button),
+ onSignInClick = { onSignInClick() },
+ modifier = modifier.padding(horizontal = 20.dp)
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun SignInScreenPreview() {
+ TerningTheme {
+ SignInScreen()
+ }
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInSideEffect.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInSideEffect.kt
new file mode 100644
index 000000000..412652e66
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInSideEffect.kt
@@ -0,0 +1,8 @@
+package com.terning.feature.onboarding.signin
+
+import androidx.annotation.StringRes
+
+sealed class SignInSideEffect {
+ data object NavigateToHome : SignInSideEffect()
+ data class ShowToast(@StringRes val message: Int) : SignInSideEffect()
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInState.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInState.kt
new file mode 100644
index 000000000..f517d6e63
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInState.kt
@@ -0,0 +1,7 @@
+package com.terning.feature.onboarding.signin
+
+import com.terning.core.state.UiState
+
+data class SignInState (
+ val accessToken: UiState = UiState.Loading
+)
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInViewModel.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInViewModel.kt
new file mode 100644
index 000000000..639b9eb71
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInViewModel.kt
@@ -0,0 +1,86 @@
+package com.terning.feature.onboarding.signin
+
+import android.content.Context
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.kakao.sdk.auth.model.OAuthToken
+import com.kakao.sdk.common.model.ClientError
+import com.kakao.sdk.common.model.ClientErrorCause
+import com.kakao.sdk.user.UserApiClient
+import com.terning.core.state.UiState
+import com.terning.feature.R
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class SignInViewModel @Inject constructor() : ViewModel() {
+
+ private val _signInState = MutableStateFlow(SignInState())
+ val signInState: StateFlow
+ get() = _signInState.asStateFlow()
+
+ private val _signInSideEffects = MutableSharedFlow()
+ val signInSideEffects: SharedFlow
+ get() = _signInSideEffects.asSharedFlow()
+
+ fun startKakaoLogIn(context: Context) {
+ if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
+ UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
+ signInResult(context, token, error)
+ }
+ } else {
+ UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
+ signInResult(context, token, error)
+ }
+ }
+ }
+
+ private fun signInResult(context: Context, token: OAuthToken?, error: Throwable?) {
+ viewModelScope.launch {
+ if (error != null) {
+ signInFailure(context, error)
+ } else if (token != null) {
+ signInSuccess(token)
+ }
+ }
+ }
+
+ private fun signInFailure(context: Context, error: Throwable?) {
+ if (error.toString().contains(KAKAO_NOT_LOGGED_IN)) {
+ UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
+ signInResult(context, token, error)
+ }
+ } else {
+ sigInCancellationOrError(error)
+ }
+ }
+
+ private fun sigInCancellationOrError(error: Throwable?) {
+ viewModelScope.launch {
+ if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
+ _signInSideEffects.emit(SignInSideEffect.ShowToast(R.string.sign_in_kakao_cancel))
+ } else {
+ _signInSideEffects.emit(SignInSideEffect.ShowToast(R.string.sign_in_kakao_login_fail))
+ }
+ }
+ }
+
+ private fun signInSuccess(token: OAuthToken) {
+ viewModelScope.launch {
+ _signInState.value =
+ _signInState.value.copy(accessToken = UiState.Success(token.accessToken))
+ _signInSideEffects.emit(SignInSideEffect.NavigateToHome)
+ }
+ }
+
+ companion object {
+ private const val KAKAO_NOT_LOGGED_IN = "statusCode=302"
+ }
+}
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/component/KakaoButton.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/component/KakaoButton.kt
new file mode 100644
index 000000000..97591bb83
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/component/KakaoButton.kt
@@ -0,0 +1,57 @@
+package com.terning.feature.onboarding.signin.component
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.terning.core.designsystem.theme.TerningTheme
+import com.terning.core.extension.noRippleClickable
+import com.terning.feature.R
+
+@Composable
+fun KakaoButton(
+ title: String,
+ modifier: Modifier = Modifier,
+ onSignInClick: () -> Unit
+) {
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .background(Color.Yellow)
+ .noRippleClickable { onSignInClick() }
+ .padding(vertical = 14.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.ic_signin_kakao),
+ contentDescription = null,
+ modifier = Modifier.padding(horizontal = 8.dp)
+ )
+ Text(
+ text = title,
+ // TODO : style 추가하기
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun KakaoButtonPreview() {
+ TerningTheme {
+ KakaoButton(
+ title = "카카오로 로그인하기",
+ onSignInClick = {}
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt
new file mode 100644
index 000000000..0c3d35760
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt
@@ -0,0 +1,30 @@
+package com.terning.feature.onboarding.signin.navigation
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavHostController
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import com.terning.core.navigation.MainTabRoute
+import com.terning.feature.onboarding.signin.SignInRoute
+import kotlinx.serialization.Serializable
+
+fun NavController.navigateSignIn(navOptions: NavOptions? = null) {
+ navigate(
+ route = SignIn,
+ navOptions = navOptions
+ )
+}
+
+fun NavGraphBuilder.signInNavGraph(
+ navHostController: NavHostController
+) {
+ composable {
+ SignInRoute(
+ navController = navHostController
+ )
+ }
+}
+
+@Serializable
+data object SignIn : MainTabRoute
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt
new file mode 100644
index 000000000..9d3d3d411
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt
@@ -0,0 +1,13 @@
+package com.terning.feature.onboarding.signup
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun SignUpRoute() {
+ SignUpScreen()
+}
+
+@Composable
+fun SignUpScreen() {
+
+}
\ No newline at end of file
diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt
new file mode 100644
index 000000000..1379d0a64
--- /dev/null
+++ b/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt
@@ -0,0 +1,25 @@
+package com.terning.feature.onboarding.signup.navigation
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import com.terning.core.navigation.MainTabRoute
+import com.terning.feature.onboarding.signup.SignUpRoute
+import kotlinx.serialization.Serializable
+
+fun NavController.navigateSignUp(navOptions: NavOptions? = null) {
+ navigate(
+ route = SignUp,
+ navOptions = navOptions
+ )
+}
+
+fun NavGraphBuilder.signUpNavGraph() {
+ composable {
+ SignUpRoute()
+ }
+}
+
+@Serializable
+data object SignUp : MainTabRoute
\ No newline at end of file
diff --git a/feature/src/main/res/drawable/ic_signin_kakao.xml b/feature/src/main/res/drawable/ic_signin_kakao.xml
new file mode 100644
index 000000000..cbe75d056
--- /dev/null
+++ b/feature/src/main/res/drawable/ic_signin_kakao.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/feature/src/main/res/drawable/img_terning_point.png b/feature/src/main/res/drawable/img_terning_point.png
new file mode 100644
index 000000000..fc2158319
Binary files /dev/null and b/feature/src/main/res/drawable/img_terning_point.png differ
diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml
index 133c0442b..71aa3bf69 100644
--- a/feature/src/main/res/values/strings.xml
+++ b/feature/src/main/res/values/strings.xml
@@ -10,4 +10,9 @@
탐색
마이페이지
+
+ 카카오로 로그인하기
+ 카카오톡 로그인에 실패했습니다
+ 로그인을 취소하였습니다
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bcce3048f..1a57fcdb2 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -74,6 +74,9 @@ foundationAndroid = "1.6.8"
material3Android = "1.2.1"
lifecycleRuntimeComposeAndroid = "2.8.2"
+## Kakao
+kakaoVersion = "2.20.1"
+
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" }
@@ -149,6 +152,8 @@ timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
ossLicense = {group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "ossVersion"}
lottie = {group = "com.airbnb.android", name = "lottie", version.ref = "lottieVersion"}
+kakao-user = {group = "com.kakao.sdk", name = "v2-user", version.ref = "kakaoVersion"}
+
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 8a2c140ec..bd88f3f5d 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -16,6 +16,9 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+
+ // KakaoSDK repository
+ maven(url = "https://devrepo.kakao.com/nexus/content/groups/public/")
}
}