diff --git a/CLAUDE.md b/CLAUDE.md
index 546a7896..d2e83b2d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -33,7 +33,7 @@ JDK 21. Gradle wrapper 사용(`./gradlew`). CI(`.github/workflows/`)는 `assembl
## 빌드에 필요한 로컬 설정
- `local.properties` 키 → `app/build.gradle.kts` 가 `BuildConfig`·manifestPlaceholder 로 주입한다:
- `BASE_URL`(Retrofit base, `@BaseUrl`), `KAKAO_NATIVE_APP_KEY`, `KAKAO_REST_API_KEY`, `KAKAO_REDIRECT_URI`, `GOOGLE_CLIENT_ID`, `GOOGLE_REDIRECT_URI`(스킴 부분이 AppAuth redirect 로 쓰임), `AMPLITUDE_API_KEY`, `TTI_SHEET_URL`(TTI 를 받는 구글 시트 Apps Script 웹앱).
+ `BASE_URL`(Retrofit base, `@BaseUrl`), `KAKAO_NATIVE_APP_KEY`, `KAKAO_NATIVE_APP_KEY_DEBUG`(debug 빌드 전용, `.debug` 패키지가 등록된 키 — 비면 위 키로 대체), `KAKAO_REST_API_KEY`, `KAKAO_REDIRECT_URI`, `GOOGLE_CLIENT_ID`, `GOOGLE_REDIRECT_URI`(스킴 부분이 AppAuth redirect 로 쓰임), `AMPLITUDE_API_KEY`, `TTI_SHEET_URL`(TTI 를 받는 구글 시트 Apps Script 웹앱), `FACEBOOK_APP_ID`·`FACEBOOK_CLIENT_TOKEN`(Meta SDK, `resValue` 문자열 리소스로 주입).
값이 비면 빈 문자열로 주입될 뿐 빌드는 통과한다 — 런타임에 조용히 죽으므로 증상이 나오면 여기부터 본다.
- `app/google-services.json` 은 커밋하지 않는다. 파일이 **있을 때만** google-services·Crashlytics 플러그인이 적용된다(`app/build.gradle.kts` 상단 조건부 apply). CI 는 시크릿에서 복원한다.
- 버전은 전부 `gradle/libs.versions.toml` 버전 카탈로그. 동적 버전(`1.+`)은 쓰지 않는다.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5048bb8c..fef63ea6 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -25,9 +25,18 @@ val localProperties =
}
val kakaoNativeAppKey: String = localProperties.getProperty("KAKAO_NATIVE_APP_KEY")?.trim().orEmpty()
+
+// 카카오는 네이티브 앱 키 하나에 패키지명 하나만 등록되므로 debug 패키지는 전용 키를 쓴다(#632)
+val kakaoNativeAppKeyDebug: String =
+ localProperties
+ .getProperty("KAKAO_NATIVE_APP_KEY_DEBUG")
+ ?.trim()
+ ?.takeIf { it.isNotEmpty() } ?: kakaoNativeAppKey
val baseUrl: String = localProperties.getProperty("BASE_URL")?.trim().orEmpty()
val amplitudeApiKey: String = localProperties.getProperty("AMPLITUDE_API_KEY")?.trim().orEmpty()
val ttiSheetUrl: String = localProperties.getProperty("TTI_SHEET_URL")?.trim().orEmpty()
+val facebookAppId: String = localProperties.getProperty("FACEBOOK_APP_ID")?.trim().orEmpty()
+val facebookClientToken: String = localProperties.getProperty("FACEBOOK_CLIENT_TOKEN")?.trim().orEmpty()
val appAuthRedirectScheme: String =
localProperties
.getProperty("GOOGLE_REDIRECT_URI")
@@ -88,6 +97,9 @@ android {
buildConfigField("String", "AMPLITUDE_API_KEY", "\"$amplitudeApiKey\"")
// TTI 를 받는 구글 시트 Apps Script 웹앱 URL. 비면 보내지 않는다(#623)
buildConfigField("String", "TTI_SHEET_URL", "\"$ttiSheetUrl\"")
+ // Meta SDK 는 숫자 앱 ID 를 meta-data 문자열 리소스로 읽어야 한다 — placeholder 로 넣으면 숫자로 파싱된다
+ resValue("string", "facebook_app_id", facebookAppId)
+ resValue("string", "facebook_client_token", facebookClientToken)
}
signingConfigs {
@@ -102,6 +114,12 @@ android {
}
buildTypes {
+ // 스토어 앱과 한 기기에 같이 설치되도록 패키지명을 가른다
+ debug {
+ applicationIdSuffix = ".debug"
+ manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoNativeAppKeyDebug
+ buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"$kakaoNativeAppKeyDebug\"")
+ }
release {
// 자격 증명이 없으면 null
signingConfig = signingConfigs.findByName("release")
@@ -127,6 +145,7 @@ android {
buildFeatures {
compose = true
buildConfig = true
+ resValues = true
}
}
@@ -211,6 +230,9 @@ dependencies {
implementation(libs.firebase.messaging)
implementation(libs.firebase.perf)
+ // Meta 앱 이벤트(광고 성과 측정). 로그인·공유 모듈은 쓰지 않는다.
+ implementation(libs.facebook.core)
+
// 프레임 jank 측정(JankStats).
implementation(libs.androidx.metrics.performance)
diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml
new file mode 100644
index 00000000..9abfbb81
--- /dev/null
+++ b/app/src/debug/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+
+
+ ruleup debug
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index de2fd175..17521da4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -122,6 +122,14 @@
android:value="androidx.startup"
tools:node="remove" />
+
+
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b8f650fa..41452380 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -72,6 +72,9 @@ zxing = "3.5.3"
# Amplitude
amplitudeAnalytics = "1.30.1"
+# Meta 앱 이벤트
+facebookCore = "19.0.0"
+
# firebase
googleservice = "4.4.4"
firebaseCrashlyticsPlugin = "3.0.6"
@@ -187,6 +190,8 @@ zxing-core = { module = "com.google.zxing:core", version.ref = "zxing" }
# amplitude
amplitude-analytics = { group = "com.amplitude", name = "analytics-android", version.ref = "amplitudeAnalytics" }
+# Meta 앱 이벤트
+facebook-core = { group = "com.facebook.android", name = "facebook-core", version.ref = "facebookCore" }
# firebase
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
diff --git a/onboarding/presentation/build.gradle.kts b/onboarding/presentation/build.gradle.kts
index 90031e6e..fb3d9281 100644
--- a/onboarding/presentation/build.gradle.kts
+++ b/onboarding/presentation/build.gradle.kts
@@ -16,6 +16,13 @@ val localProperties =
}
val kakaoNativeAppKey: String = localProperties.getProperty("KAKAO_NATIVE_APP_KEY")?.trim().orEmpty()
+
+// 카카오는 네이티브 앱 키 하나에 패키지명 하나만 등록되므로 debug 패키지는 전용 키를 쓴다(#632)
+val kakaoNativeAppKeyDebug: String =
+ localProperties
+ .getProperty("KAKAO_NATIVE_APP_KEY_DEBUG")
+ ?.trim()
+ ?.takeIf { it.isNotEmpty() } ?: kakaoNativeAppKey
val googleClientId: String = localProperties.getProperty("GOOGLE_CLIENT_ID")?.trim().orEmpty()
val googleRedirectUri: String = localProperties.getProperty("GOOGLE_REDIRECT_URI")?.trim().orEmpty()
val kakaoRestApiKey: String = localProperties.getProperty("KAKAO_REST_API_KEY")?.trim().orEmpty()
@@ -38,6 +45,13 @@ android {
buildConfigField("String", "KAKAO_REDIRECT_URI", "\"$kakaoRedirectUri\"")
}
+ buildTypes {
+ debug {
+ manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoNativeAppKeyDebug
+ buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"$kakaoNativeAppKeyDebug\"")
+ }
+ }
+
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11