diff --git a/build-logic/src/main/java/com/neki/android/buildlogic/extensions/Android.kt b/build-logic/src/main/java/com/neki/android/buildlogic/extensions/Android.kt index 9d8291e26..966861048 100644 --- a/build-logic/src/main/java/com/neki/android/buildlogic/extensions/Android.kt +++ b/build-logic/src/main/java/com/neki/android/buildlogic/extensions/Android.kt @@ -3,9 +3,9 @@ package com.neki.android.buildlogic.extensions import com.android.build.api.dsl.CommonExtension import com.neki.android.buildlogic.const.BuildConst import org.gradle.api.Project -import org.gradle.api.plugins.ExtensionAware import org.gradle.kotlin.dsl.dependencies -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension internal fun Project.configureAndroid( commonExtension: CommonExtension<*, *, *, *, *, *>, @@ -22,18 +22,14 @@ internal fun Project.configureAndroid( targetCompatibility = BuildConst.JAVA_VERSION } - configureAndroidOptions { - jvmTarget = BuildConst.JDK_VERSION.toString() - } - dependencies { add("detektPlugins", libs.findLibrary("detekt.formatting").get()) } } -} -internal fun CommonExtension<*, *, *, *, *, *>.configureAndroidOptions( - block: KotlinJvmOptions.() -> Unit, -) { - (this as ExtensionAware).extensions.configure("kotlinOptions", block) + extensions.configure("kotlin") { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(BuildConst.JDK_VERSION.toString())) + } + } } diff --git a/core/data-api/src/main/java/com/neki/android/core/dataapi/auth/AuthCacheManager.kt b/core/data-api/src/main/java/com/neki/android/core/dataapi/auth/AuthCacheManager.kt deleted file mode 100644 index 02653e70c..000000000 --- a/core/data-api/src/main/java/com/neki/android/core/dataapi/auth/AuthCacheManager.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.neki.android.core.dataapi.auth - -interface AuthCacheManager { - fun invalidateTokenCache() -} diff --git a/core/data-api/src/main/java/com/neki/android/core/dataapi/repository/TokenRepository.kt b/core/data-api/src/main/java/com/neki/android/core/dataapi/repository/TokenRepository.kt index 2518c6a39..68fc3d6bd 100644 --- a/core/data-api/src/main/java/com/neki/android/core/dataapi/repository/TokenRepository.kt +++ b/core/data-api/src/main/java/com/neki/android/core/dataapi/repository/TokenRepository.kt @@ -10,5 +10,5 @@ interface TokenRepository { fun hasTokens(): Flow fun getAccessToken(): Flow fun getRefreshToken(): Flow - suspend fun clearTokens() + suspend fun clearTokensWithAuthCache() } diff --git a/core/data/src/main/java/com/neki/android/core/data/remote/di/NetworkModule.kt b/core/data/src/main/java/com/neki/android/core/data/remote/di/NetworkModule.kt index 0a795846a..5117fc066 100644 --- a/core/data/src/main/java/com/neki/android/core/data/remote/di/NetworkModule.kt +++ b/core/data/src/main/java/com/neki/android/core/data/remote/di/NetworkModule.kt @@ -6,7 +6,6 @@ import com.neki.android.core.data.remote.model.request.RefreshTokenRequest import com.neki.android.core.data.remote.model.response.AuthResponse import com.neki.android.core.data.remote.model.response.BasicResponse import com.neki.android.core.data.remote.qualifier.UploadHttpClient -import com.neki.android.core.dataapi.auth.AuthCacheManager import com.neki.android.core.dataapi.auth.AuthEventManager import com.neki.android.core.dataapi.repository.TokenRepository import dagger.Module @@ -19,14 +18,12 @@ import io.ktor.client.engine.android.Android import io.ktor.client.plugins.DefaultRequest import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.auth.Auth -import io.ktor.client.plugins.auth.providers.BearerAuthProvider import io.ktor.client.plugins.auth.providers.BearerTokens import io.ktor.client.plugins.auth.providers.bearer import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logger import io.ktor.client.plugins.logging.Logging -import io.ktor.client.plugins.plugin import io.ktor.client.request.header import io.ktor.client.request.post import io.ktor.client.request.setBody @@ -35,7 +32,6 @@ import io.ktor.http.HttpHeaders import io.ktor.http.encodedPath import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.flow.first -import dagger.Lazy import kotlinx.serialization.json.Json import timber.log.Timber import javax.inject.Singleton @@ -62,19 +58,6 @@ internal object NetworkModule { explicitNulls = false } - @Provides - @Singleton - fun provideAuthCacheManager( - httpClient: Lazy, - ): AuthCacheManager = object : AuthCacheManager { - override fun invalidateTokenCache() { - httpClient.get().plugin(Auth).providers - .filterIsInstance() - .firstOrNull() - ?.clearToken() - } - } - @Provides @Singleton fun provideHttpClient( @@ -89,6 +72,8 @@ internal object NetworkModule { install(Auth) { bearer { + cacheTokens = !BuildConfig.DEBUG + loadTokens { if (tokenRepository.hasTokens().first()) { BearerTokens( @@ -120,7 +105,7 @@ internal object NetworkModule { ) } catch (e: Exception) { Timber.e(e) - tokenRepository.clearTokens() + tokenRepository.clearTokensWithAuthCache() authEventManager.emitTokenExpired() null } diff --git a/core/data/src/main/java/com/neki/android/core/data/repository/impl/TokenRepositoryImpl.kt b/core/data/src/main/java/com/neki/android/core/data/repository/impl/TokenRepositoryImpl.kt index e17495b51..61dd98073 100644 --- a/core/data/src/main/java/com/neki/android/core/data/repository/impl/TokenRepositoryImpl.kt +++ b/core/data/src/main/java/com/neki/android/core/data/repository/impl/TokenRepositoryImpl.kt @@ -5,8 +5,11 @@ import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import com.neki.android.core.common.crypto.CryptoManager -import com.neki.android.core.dataapi.auth.AuthCacheManager import com.neki.android.core.dataapi.repository.TokenRepository +import dagger.Lazy +import io.ktor.client.HttpClient +import io.ktor.client.plugins.auth.authProvider +import io.ktor.client.plugins.auth.providers.BearerAuthProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import com.neki.android.core.data.local.di.TokenDataStore @@ -14,7 +17,7 @@ import javax.inject.Inject class TokenRepositoryImpl @Inject constructor( @TokenDataStore private val dataStore: DataStore, - private val authCacheManager: AuthCacheManager, + private val httpClient: Lazy, ) : TokenRepository { companion object { @@ -30,7 +33,6 @@ class TokenRepositoryImpl @Inject constructor( preferences[ACCESS_TOKEN] = CryptoManager.encrypt(accessToken) preferences[REFRESH_TOKEN] = CryptoManager.encrypt(refreshToken) } - authCacheManager.invalidateTokenCache() } override fun hasTokens(): Flow { @@ -54,11 +56,11 @@ class TokenRepositoryImpl @Inject constructor( } } - override suspend fun clearTokens() { + override suspend fun clearTokensWithAuthCache() { + httpClient.get().authProvider()?.clearToken() dataStore.edit { preferences -> preferences.remove(ACCESS_TOKEN) preferences.remove(REFRESH_TOKEN) } - authCacheManager.invalidateTokenCache() } } diff --git a/feature/mypage/impl/src/main/java/com/neki/android/feature/mypage/impl/main/MyPageViewModel.kt b/feature/mypage/impl/src/main/java/com/neki/android/feature/mypage/impl/main/MyPageViewModel.kt index 29ccfbdd6..e86bd2815 100644 --- a/feature/mypage/impl/src/main/java/com/neki/android/feature/mypage/impl/main/MyPageViewModel.kt +++ b/feature/mypage/impl/src/main/java/com/neki/android/feature/mypage/impl/main/MyPageViewModel.kt @@ -178,7 +178,7 @@ internal class MyPageViewModel @Inject constructor( } private fun logout(postSideEffect: (MyPageEffect) -> Unit) = viewModelScope.launch { - tokenRepository.clearTokens() + tokenRepository.clearTokensWithAuthCache() postSideEffect(MyPageEffect.LogoutWithKakao) } @@ -189,7 +189,7 @@ internal class MyPageViewModel @Inject constructor( reduce { copy(isLoading = true) } authRepository.withdrawAccount() .onSuccess { - tokenRepository.clearTokens() + tokenRepository.clearTokensWithAuthCache() authRepository.setCompletedOnboarding(false) reduce { copy(isLoading = false) } postSideEffect(MyPageEffect.UnlinkWithKakao) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d5abf1d2..3311076b0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ agp = "8.13.1" annotationExperimental = "1.5.1" cameraX = "1.5.2" composeStableMarker = "1.0.7" -kotlin = "2.1.0" +kotlin = "2.3.0" coreKtx = "1.15.0" junit = "4.13.2" junitVersion = "1.3.0" @@ -11,13 +11,12 @@ espressoCore = "3.7.0" lifecycleRuntimeKtx = "2.6.1" activityCompose = "1.9.3" composeBom = "2025.08.01" -jetbrainsKotlinJvm = "2.1.0" -ksp = "2.1.0-1.0.29" +jetbrainsKotlinJvm = "2.3.0" +ksp = "2.3.0" appcompat = "1.7.1" kotlinxSerializationJson = "1.9.0" -jetbrainsKotlinJvmVersion = "2.1.0" -hilt = "2.54" -ktor = "2.3.12" +hilt = "2.58" +ktor = "3.4.0" androidxDatastore = "1.1.2" kotlinxCoroutines = "1.8.1" paging = "3.3.6" @@ -144,7 +143,7 @@ android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvmVersion" } +jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } android-library = { id = "com.android.library", version.ref = "agp" }