-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/kakao login #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
27beb2f
44204c8
7d2a4ba
e5a5876
6151705
c7943ee
c29d3b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,14 +1,42 @@ | ||||||||||||||||
| import java.util.Properties | ||||||||||||||||
|
|
||||||||||||||||
| plugins { | ||||||||||||||||
| alias(libs.plugins.hyunjung.cherrydan.android.application.compose) | ||||||||||||||||
| alias(libs.plugins.hyunjung.cherrydan.jvm.ktor) | ||||||||||||||||
| alias(libs.plugins.mapsplatform.secrets.plugin) | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| secrets { | ||||||||||||||||
| defaultPropertiesFileName = "secrets.properties" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| android { | ||||||||||||||||
| namespace = "com.hyunjung.cherrydan" | ||||||||||||||||
|
|
||||||||||||||||
| defaultConfig { | ||||||||||||||||
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||||||||||||||
|
|
||||||||||||||||
| buildConfigField( | ||||||||||||||||
| "String", | ||||||||||||||||
| "BASE_URL", | ||||||||||||||||
| "\"https://cherrydan.com\"" | ||||||||||||||||
| ) | ||||||||||||||||
|
|
||||||||||||||||
| val secretsFile = file("${rootProject.projectDir}/secrets.properties") | ||||||||||||||||
| val kakaoKey = if (secretsFile.exists()) { | ||||||||||||||||
| val properties = Properties() | ||||||||||||||||
| properties.load(secretsFile.inputStream()) | ||||||||||||||||
| properties.getProperty("KAKAO_NATIVE_APP_KEY", "") | ||||||||||||||||
| } else { | ||||||||||||||||
| "" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey" | ||||||||||||||||
| manifestPlaceholders["kakaoKey"] = kakaoKey | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nil-safe placeholder – avoid producing an invalid scheme If - manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey"
- manifestPlaceholders["kakaoKey"] = kakaoKey
+ require(kakaoKey.isNotBlank()) { "KAKAO_NATIVE_APP_KEY is missing" }
+ manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey"
+ manifestPlaceholders["kakaoKey"] = kakaoKey📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| buildFeatures { | ||||||||||||||||
| buildConfig = true | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -57,14 +85,21 @@ dependencies { | |||||||||||||||
| api(libs.play.feature.delivery) | ||||||||||||||||
| api(libs.play.review) | ||||||||||||||||
|
|
||||||||||||||||
| implementation(projects.feature.auth) | ||||||||||||||||
| implementation(projects.feature.home) | ||||||||||||||||
| implementation(projects.feature.notification) | ||||||||||||||||
| implementation(projects.feature.search) | ||||||||||||||||
|
|
||||||||||||||||
| implementation(projects.core.presentation.designsystem) | ||||||||||||||||
| implementation(projects.core.presentation.ui) | ||||||||||||||||
| implementation(projects.core.domain) | ||||||||||||||||
| implementation(projects.core.data) | ||||||||||||||||
| implementation(projects.core.database) | ||||||||||||||||
| implementation(projects.core.network) | ||||||||||||||||
| implementation(projects.core.common) | ||||||||||||||||
|
|
||||||||||||||||
| implementation(projects.feature.auth) | ||||||||||||||||
| implementation(projects.feature.home) | ||||||||||||||||
| implementation(projects.feature.notification) | ||||||||||||||||
| implementation(projects.feature.search) | ||||||||||||||||
| // Kakao SDK | ||||||||||||||||
| implementation(libs.kakao.auth) | ||||||||||||||||
| implementation(libs.kakao.common) | ||||||||||||||||
| implementation(libs.kakao.user) | ||||||||||||||||
| } | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package com.hyunjung.cherrydan | ||
|
|
||
| import android.app.Application | ||
| import com.hyunjung.core.data.di.dataModule | ||
| import com.hyunjung.core.network.di.networkModule | ||
| import com.hyunjung.feature.auth.di.authViewModelModule | ||
| import com.kakao.sdk.common.KakaoSdk | ||
| import org.koin.android.ext.koin.androidContext | ||
| import org.koin.core.context.startKoin | ||
| import timber.log.Timber | ||
|
|
||
| class CherrydanApplication : Application() { | ||
|
|
||
| override fun onCreate() { | ||
| super.onCreate() | ||
|
|
||
| // Timber 초기화 (가장 먼저) | ||
| if (BuildConfig.DEBUG) { | ||
| Timber.plant(Timber.DebugTree()) | ||
| } | ||
|
|
||
| // 카카오 앱키 확인 | ||
| val kakaoAppKey = BuildConfig.KAKAO_NATIVE_APP_KEY | ||
| Timber.d("Kakao App Key: $kakaoAppKey") | ||
|
|
||
| if (kakaoAppKey.isEmpty()) { | ||
| Timber.e("Kakao App Key가 설정되지 않았습니다!") | ||
| } | ||
|
|
||
| // Kakao SDK 초기화 | ||
| KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY) | ||
|
|
||
| // Koin 초기화 | ||
| startKoin { | ||
| androidContext(this@CherrydanApplication) | ||
| modules( | ||
| authViewModelModule, | ||
| dataModule, | ||
| networkModule | ||
| // 다른 모듈들도 여기에 추가 | ||
| ) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,84 @@ | ||
| package com.hyunjung.cherrydan | ||
|
|
||
| import android.content.pm.PackageManager | ||
| import android.os.Bundle | ||
| import android.util.Base64 | ||
| import android.util.Log | ||
| import android.widget.Toast | ||
| import androidx.activity.ComponentActivity | ||
| import androidx.activity.compose.setContent | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableStateOf | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.navigation.compose.NavHost | ||
| import androidx.navigation.compose.composable | ||
| import androidx.navigation.compose.rememberNavController | ||
| import com.hyunjung.cherrydan.navigation.AppNavigation | ||
| import com.hyunjung.core.presentation.designsystem.CherrydanTheme | ||
| import com.hyunjung.feature.auth.login.LogInScreenRoot | ||
| import com.hyunjung.feature.auth.splash.SplashScreen | ||
| import com.hyunjung.feature.home.navigation.HomeNavigation | ||
| import timber.log.Timber | ||
| import java.security.MessageDigest | ||
|
|
||
| class MainActivity : ComponentActivity() { | ||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| setContent { | ||
| CherrydanTheme { | ||
| HomeNavigation() | ||
| var isLoggedIn by remember { mutableStateOf(false) } | ||
|
|
||
| if (isLoggedIn) { | ||
| HomeNavigation() | ||
| } else { | ||
| val navController = rememberNavController() | ||
|
|
||
| NavHost( | ||
| navController = navController, | ||
| startDestination = "splash" | ||
| ) { | ||
| composable("splash") { | ||
| SplashScreen( | ||
| onSplashFinished = { | ||
| // TODO: 실제로는 토큰 확인 후 결정 | ||
| // if (hasValidToken) { isLoggedIn = true } else { navigate to login } | ||
| navController.navigate("login") { | ||
| popUpTo("splash") { inclusive = true } | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| composable("login") { | ||
| LogInScreenRoot( | ||
| onKakaoLogInClick = { }, | ||
| onNaverLogInClick = { }, | ||
| onGoogleLogInClick = { }, | ||
| onLoginSuccess = { isLoggedIn = true } | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override fun onResume() { | ||
| super.onResume() | ||
| Timber.d("MainActivity onResume called") | ||
| } | ||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| private fun MainActivityPreview() { | ||
| CherrydanTheme { | ||
| HomeNavigation() | ||
| AppNavigation( | ||
| navController = rememberNavController() | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package com.hyunjung.cherrydan.navigation | ||
|
|
||
| import androidx.compose.runtime.Composable | ||
| import androidx.navigation.NavHostController | ||
| import androidx.navigation.compose.NavHost | ||
| import androidx.navigation.compose.composable | ||
| import androidx.navigation.compose.rememberNavController | ||
| import com.hyunjung.feature.auth.login.LogInScreenRoot | ||
| import com.hyunjung.feature.auth.splash.SplashScreen | ||
| import com.hyunjung.feature.home.navigation.HomeNavigation | ||
|
|
||
| @Composable | ||
| fun AppNavigation( | ||
| navController: NavHostController = rememberNavController() | ||
| ) { | ||
| NavHost( | ||
| navController = navController, | ||
| startDestination = "splash" | ||
| ) { | ||
| composable("splash") { | ||
| SplashScreen( | ||
| onSplashFinished = { | ||
| navController.navigate("login") { | ||
| popUpTo("splash") { inclusive = true } | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| composable("login") { | ||
| LogInScreenRoot( | ||
| onKakaoLogInClick = { | ||
| navController.navigate("home") { | ||
| popUpTo("login") { inclusive = true } | ||
| } | ||
| }, | ||
| onNaverLogInClick = { | ||
| navController.navigate("home") { | ||
| popUpTo("login") { inclusive = true } | ||
| } | ||
| }, | ||
| onGoogleLogInClick = { | ||
| navController.navigate("home") { | ||
| popUpTo("login") { inclusive = true } | ||
| } | ||
| }, | ||
| onLoginSuccess = { | ||
| navController.navigate("home") { | ||
| popUpTo("login") { inclusive = true } | ||
| } | ||
| } | ||
hyunjung-choi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
| } | ||
| composable("home") { | ||
| HomeNavigation() | ||
| } | ||
| // authGraph(navController) | ||
| // | ||
| // mainGraph(navController) | ||
| // | ||
| // profileGraph(navController) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Hard-coded
BASE_URLcouples release & staging buildsA single, immutable URL baked into all variants prevents you from pointing staging / QA builds at a different backend without another PR. Consider turning it into a variant-specific value or loading it from
gradle.properties/ the secrets plugin.🏁 Script executed:
Length of output: 249
Make
BASE_URLconfigurable via project propertyHard-coding the same endpoint in all variants couples your builds to a single backend. Instead, read
BASE_URLfrom a Gradle property (e.g. ingradle.propertiesor via-PBASE_URL) with a fallback.• Location:
app/build.gradle.kts(around lines 19–24)• Steps:
gradle.properties, add:BASE_URL=https://cherrydan.comapp/build.gradle.kts, replace the hard-coded field with:• Optional: If you require a dedicated “staging” variant, define a
stagingbuildType underandroid.buildTypesand configure it (e.g.,initWith(release)) so you can run./gradlew assembleStagingdirectly.🤖 Prompt for AI Agents