Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions SPOTeam_android/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions SPOTeam_android/.idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 0 additions & 7 deletions SPOTeam_android/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

103 changes: 69 additions & 34 deletions SPOTeam_android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import java.util.Properties

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
id("kotlin-kapt") // kapt 플러그인 직접 선언
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
id("kotlin-kapt")
}
val properties = Properties().apply {
load(project.rootProject.file("local.properties").inputStream())
}

android {
Expand All @@ -18,6 +24,11 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "BASE_URL", properties["base.url"].toString())
buildConfigField("String", "KAKAO_NATIVE_KEY", "\"${properties["kakao.native.key"]}\"")
buildConfigField("String", "NAVER_CLIENT_ID", "\"${properties["naver.client.id"]}\"")
buildConfigField("String", "NAVER_CLIENT_SECRET", "\"${properties["naver.client.secret"]}\"")
buildConfigField("String", "PUBLIC_API_KEY", "\"${properties["public.api.key"]}\"")
}

buildTypes {
Expand All @@ -29,60 +40,86 @@ android {
)
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "11"
}

buildFeatures {
viewBinding = true
dataBinding = true
buildConfig = true
}
}

dependencies {
implementation(libs.androidx.splashscreen)
implementation(libs.circleimageview)
// AndroidX & UI
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.androidx.activity)
implementation(libs.flexbox)
implementation(libs.kakaoSdkAll)
implementation(libs.kakaoSdkUser)
implementation(libs.androidx.recyclerview)
implementation(libs.androidx.viewpager2)
implementation(libs.androidx.activity)
implementation(libs.androidx.splashscreen)
implementation(libs.androidx.material3.android)
implementation(libs.androidx.media3.common)
implementation(libs.filament.android)
implementation(libs.firebase.crashlytics.buildtools)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation(libs.androidx.viewpager2)
implementation(libs.flexbox)

// Lifecycle & Navigation
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)

// Network & Serialization
implementation(libs.retrofit)
implementation(libs.retrofit.converter.scalars)
implementation(libs.kotlin.stdlib)
implementation(libs.gson)
implementation(libs.glide)
implementation(libs.retrofit.kotlinx.serialization.json)

// Hilt
implementation(libs.hilt)
kapt(libs.hilt.compiler)

// Room
implementation(libs.room.runtime)
implementation(libs.room.ktx)
ksp("androidx.room:room-compiler:2.6.1")
implementation ("com.github.prolificinteractive:material-calendarview:2.0.1")
ksp(libs.room.compiler)

// Glide & Calendar & Coil
implementation(libs.glide)
implementation(libs.circleimageview)
implementation("com.github.prolificinteractive:material-calendarview:2.0.1")

// Login SDKs
implementation(libs.kakaoSdkAll)
implementation(libs.kakaoSdkUser)
implementation("com.navercorp.nid:oauth:5.9.1")
implementation("com.squareup.retrofit2:converter-simplexml:2.9.0")
implementation("com.google.dagger:hilt-android:2.51.1")
kapt("com.google.dagger:hilt-android-compiler:2.51.1")

// Date-Time
implementation("com.jakewharton.threetenabp:threetenabp:1.4.4")

// Firebase & Crashlytics
implementation(libs.firebase.crashlytics.buildtools)

// 기타
implementation(libs.filament.android)
implementation("com.squareup.retrofit2:converter-simplexml:2.9.0")

// Kotlin
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.serialization.json)

// Test
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}

kapt {
Expand All @@ -92,8 +129,6 @@ kapt {
correctErrorTypes = true
}

configurations {
all {
exclude(group = "com.android.support", module = "support-compat")
}
}
configurations.all {
exclude(group = "com.android.support", module = "support-compat")
}
52 changes: 11 additions & 41 deletions SPOTeam_android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

<application
android:name=".GlobalApplication"
android:name=".SpotApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -16,69 +16,46 @@
android:theme="@style/Theme.SPOTeam_android"
android:usesCleartextTraffic="true"
tools:targetApi="34">
<activity
android:name=".login.EmailVerificationActivity"
android:exported="false" />
<activity
android:name=".login.NicNameActivity"
android:exported="false" />
<activity
android:name=".login.NormalLoginActivity"
android:exported="false" />

<service
android:name=".ui.study.StudyRegisterApiService"
android:enabled="true"
android:exported="true" />
<service
android:name=".login.LoginAPiService"
android:enabled="true"
android:exported="true" />

<activity
android:name=".ui.study.MyStudyPostContentActivity"
android:exported="false" />
<activity
android:name=".login.LocationSearchActivity"
android:exported="false" />
<activity
android:name=".login.LogoutActivity"
android:name=".presentation.login.checklist.CheckListStudyPurposeActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".ui.community.CommunityContentActivity"
android:exported="false" />
<activity
android:name=".checklist.CheckListLocationActivity"
android:name=".presentation.login.checklist.CheckListCategoryActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".checklist.CheckListStudyPurposeActivity"
android:name=".presentation.login.checklist.LocationSearchActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".checklist.CheckListCategoryActivity"
android:name=".presentation.login.checklist.CheckListLocationActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".login.RegisterInformation"
android:name=".presentation.login.nickname.NicknameActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />

</activity>
<activity
android:name=".presentation.login.checklist.RegisterInformation"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="false">
Expand All @@ -92,14 +69,7 @@

</activity>
<activity
android:name=".login.CellPhoneLoginActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".login.StartLoginActivity"
android:name=".presentation.login.StartLoginActivity"
android:exported="true"
android:theme="@style/Theme.SPOTeam_android.SplashScreen">
<meta-data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.example.spoteam_android.interceptor

import android.content.Intent
import com.example.spoteam_android.AuthApiService
import com.example.spoteam_android.data.login.datasource.local.TokenDataSource
import com.example.spoteam_android.presentation.login.StartLoginActivity
import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.Interceptor
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Inject

class AuthInterceptor @Inject constructor(
private val tokenDataSource: TokenDataSource,
@ApplicationContext private val context: android.content.Context
) : Interceptor {

override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val currentToken = tokenDataSource.getAccessToken()

if (!currentToken.isNullOrEmpty()) {
request = request.newBuilder()
.header("Authorization", "Bearer $currentToken")
.build()
}

var response = chain.proceed(request)

if (response.code == 401 || response.code == 400) {
synchronized(this) {
val updatedToken = tokenDataSource.getAccessToken()
val token = if (currentToken != updatedToken) {
updatedToken
} else {
refreshToken()?.also { tokenDataSource.saveTokens(it, tokenDataSource.getRefreshToken() ?: "") }
}

token?.let {
response.close()
request = request.newBuilder()
.header("Authorization", "Bearer $it")
.build()
return chain.proceed(request)
} ?: run {
handleInvalidRefreshToken()
}
}
}
return response
}

private fun refreshToken(): String? {
val refreshToken = tokenDataSource.getRefreshToken() ?: return null
val retrofit = Retrofit.Builder()
.baseUrl("https://www.teamspot.site/")
.addConverterFactory(GsonConverterFactory.create())
.build()

val authApi = retrofit.create(AuthApiService::class.java)
val response = authApi.refreshToken(refreshToken).execute()

return if (response.isSuccessful) {
val body = response.body()
if (body?.isSuccess == true) {
body.result?.accessToken
} else {
if (body?.code == "COMMON4009") handleInvalidRefreshToken()
null
}
} else {
null
}
}

private fun handleInvalidRefreshToken() {
tokenDataSource.saveTokens("", "")
val intent = Intent(context, StartLoginActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
context.startActivity(intent)
}
}
Loading