Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/android-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Android CI

on:
push: # 코드 푸시 이벤트에 대한 설정
branches: [ "develop" ] # "develop" 브랜치에 푸시될 때만 트리거된다.
pull_request: # 풀 리퀘스트 이벤트에 대한 설정
branches: [ "develop" ] # "develop" 브랜치로의 풀 리퀘스트가 생성될 때만 트리거된다.

jobs: # CI에서 수행할 작업을 정의한다.
ci-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
Copy link

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'cache: gradle' option in setup-java is redundant since you're already using a separate Gradle cache action below. Remove this line to avoid potential caching conflicts.

Suggested change
cache: gradle

Copilot uses AI. Check for mistakes.

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/buildSrc/**/*.kt') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Generate local.properties
run: |
echo '${{ secrets.LOCAL_PROPERTIES }}' >> ./local.properties

- name: Generate google-services.json
run: |
echo '${{ secrets.GOOGLE_SERVICES }}' >> ./app/google-services.json

# - name: Code style checks
# run: |
# ./gradlew detekt

- name: Run build
run: ./gradlew assembleDebug --stacktrace

63 changes: 63 additions & 0 deletions .github/workflows/firebase-app-distribution-debug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Build & upload to Firebase App Distribution

on:
push:
branches:
- main

jobs:
cd-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/buildSrc/**/*.kt') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Prepare keystore dir
run: mkdir -p keystore

- name: Decode And Save Keystore Base64
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore/keystore.jks
- name: Decode And Save Debug Keystore Base64
run: |
echo "${{ secrets.DEBUG_KEYSTORE_BASE64 }}" | base64 -d > debug.keystore
- name: Generate local.properties
run: |
echo '${{ secrets.LOCAL_PROPERTIES }}' >> ./local.properties
- name: Generate google-services.json
run: |
echo '${{ secrets.GOOGLE_SERVICES }}' >> ./app/google-services.json
- name: Build debug APK
run: ./gradlew assembleDebug

- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
groups: testers
file: app/build/outputs/apk/debug/app-debug.apk
# releaseNotes: ${{ steps.firebase_release_note.outputs.notes }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,5 @@ fabric.properties
### AndroidStudio Patch ###

!/gradle/wrapper/gradle-wrapper.jar
/app/debug/output-metadata.json
/app/build/outputs/**/output-metadata.json
26 changes: 25 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.firebase.crashlytics)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

CI/CD와 Firebase 구성 검증 스크립트 제안

워크플로우와 설정이 잘 맞물리는지 자동 점검해 보시죠. 아래 스크립트는 플러그인/파일/NDK 사용 여부 등을 빠르게 확인합니다.

Also applies to: 119-121, 36-43


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check google-services plugin usage =="
rg -n $'plugins\\s*\\{[\\s\\S]*?\\}' -A 50 -g "*build.gradle*" -g "*build.gradle.kts*" | rg -n "com.google.gms.google-services" || echo "google-services plugin not found in any module."

echo "== Check google-services.json existence under app =="
fd -H "google-services.json" -a || echo "google-services.json not found in repo (might be injected in CI)."

echo "== Check Crashlytics NDK vs native code presence =="
fd -t d "cpp|jni|jniLibs" -HI || true
rg -n "externalNativeBuild|ndk\\s*\\{" -g "*build.gradle*" -g "*build.gradle.kts*" || echo "No obvious NDK build config found."

echo "== Check accidental Espresso implementation in app module =="
rg -n "implementation\\(.*espresso" app/build.gradle.kts || echo "No Espresso implementation found in app/build.gradle.kts (good)."

Length of output: 1031


CI/CD 및 Firebase 설정 검증 필요

스크립트 실행 결과 다음 문제가 확인되었습니다:

  • com.google.gms.google-services 플러그인(app/build.gradle.kts 등)에 적용되어 있지 않음
  • app/google-services.json 파일이 레포지토리에 존재하지 않음 (CI 주입 방식이라면 .gitignore·설정 검토 필요)
  • Crashlytics의 NDK 빌드 설정(externalNativeBuild 혹은 ndk { … })이 없음
  • 81행(app/build.gradle.kts)에 Espresso(core) 의존성이 implementation으로 잘못 지정(테스트 전용은 androidTestImplementation으로 변경)

해결 방안:

  • 각 모듈의 build.gradle.ktsplugins { id("com.google.gms.google-services") } 추가
  • app/google-services.json 위치 및 주입 방식 검토/보완
  • NDK 기반 Crashlytics 설정 추가 여부 검토
  • Espresso 의존성을 테스트 스코프로 이동(androidTestImplementation)
🤖 Prompt for AI Agents
In app/build.gradle.kts around line 8 (and related module build files), the
Google Services plugin is not applied and Crashlytics/CI setup is incomplete;
add plugins { id("com.google.gms.google-services") } to the app module (and
other modules that need Firebase) and verify app/google-services.json is
provided or injected by CI (check .gitignore and CI secret/file injection
steps); ensure Crashlytics NDK settings are configured if your project uses
native code (add externalNativeBuild/ndk { … } Crashlytics-related config or
confirm NDK not used); and at line 81 move the Espresso dependency from
implementation to androidTestImplementation so it’s scoped to instrumentation
tests.

💡 Verification agent

🧩 Analysis chain

Firebase Analytics/Crashlytics 연동에 google-services 플러그인 누락

Crashlytics 플러그인은 추가되었지만, google-services.json 리소스 처리와 기본 초기화를 위해 com.google.gms.google-services 플러그인이 필요합니다. 현재 상태에선 Firebase Analytics/Crashlytics 설정값이 빌드에 반영되지 않을 수 있어요.

아래처럼 플러그인을 함께 적용해 주세요.

 plugins {
   alias(libs.plugins.android.application)
   alias(libs.plugins.kotlin.android)
   alias(libs.plugins.kotlin.compose)
   alias(libs.plugins.kotlin.serialization)
   alias(libs.plugins.firebase.crashlytics)
+  id("com.google.gms.google-services")
   id("com.google.dagger.hilt.android") // Hilt 플러그인 추가
   kotlin("kapt") // Hilt를 위한 kapt 추가
 }

또한 app/google-services.json 존재 여부와 CI에서의 주입 로직을 확인해 주세요. 필요 시 libs.versions.tomlgoogle-services 플러그인 버전도 정의해 두면 좋아요.


google-services 플러그인 적용 여부와 google-services.json 파일 존재 여부를 확인하기 위해 아래 스크립트를 실행합니다.


🏁 Script executed:

#!/usr/bin/env bash
set -e

echo "1. Build 스크립트에서 com.google.gms.google-services 플러그인 검색:"
rg -n "com\\.google\\.gms\\.google-services" --glob "*.{gradle,gradle.kts}" || true

echo "2. 버전 카탈로그(libs.versions.toml)에서 google-services alias 검색:"
rg -n "google-services" --glob "libs.versions.toml" || true

echo "3. 프로젝트에서 google-services.json 파일 존재 확인:"
fd google-services.json || true

Length of output: 512


com.google.gms.google-services 플러그인 & google-services.json 누락 확인

Firebase Analytics/Crashlytics 연동을 제대로 하려면 아래 항목을 반영해주세요:

• app/build.gradle.kts → plugins 블록에 플러그인 추가

 plugins {
   alias(libs.plugins.android.application)
   alias(libs.plugins.kotlin.android)
   alias(libs.plugins.kotlin.compose)
   alias(libs.plugins.kotlin.serialization)
   alias(libs.plugins.firebase.crashlytics)
+  id("com.google.gms.google-services")
   id("com.google.dagger.hilt.android")
   kotlin("kapt")
 }

• app/google-services.json 파일이 프로젝트에 존재하는지 확인
• CI/CD 환경에서 google-services.json 주입 로직 점검
• (선택) libs.versions.toml에 google-services 플러그인 버전 alias 등록

위 수정 사항들을 적용하면 Firebase 설정이 빌드에 정상 반영됩니다! 🤙

🤖 Prompt for AI Agents
In app/build.gradle.kts around line 8, the Firebase Google Services Gradle
plugin is not applied; update the plugins block to add the
com.google.gms.google-services plugin, ensure the app/google-services.json file
is present in the repo or injected at CI time (and adjust CI secrets/job to copy
it into the app module before build), and optionally add an alias for the
google-services plugin in libs.versions.toml and reference that alias from the
plugins block so versions are managed centrally.

id("com.google.dagger.hilt.android") // Hilt 플러그인 추가
kotlin("kapt") // Hilt를 위한 kapt 추가
}
Expand Down Expand Up @@ -32,6 +33,24 @@ android {

}

signingConfigs {
val debugKeystore = rootProject.file("debug.keystore")
if (debugKeystore.exists()) {
getByName("debug") {
storeFile = debugKeystore
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}
getByName("debug") {
storeFile = file("$rootDir/debug.keystore")
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}

buildTypes {
release {
isMinifyEnabled = false
Expand Down Expand Up @@ -98,12 +117,17 @@ dependencies {
// Kakao SDK
implementation("com.kakao.sdk:v2-all:2.20.6")
implementation("com.kakao.sdk:v2-user:2.20.6") // 카카오 로그인 API 모듈
implementation ("com.kakao.maps.open:android:2.12.8") // 카카오 맵 API
implementation("com.kakao.maps.open:android:2.12.8") // 카카오 맵 API

// coil
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
implementation(libs.coil.svg)

// Firebase
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.crashlytics.ndk)
implementation(libs.firebase.analytics)
Comment on lines +128 to +130
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Crashlytics NDK 의존성 재검토 + 디버그 수집 비활성화 권장

  • NDK를 사용하지 않는다면 firebase-crashlytics-ndk는 불필요한 의존성입니다. 일반 crashlytics-ktx로 교체해 용량/빌드시간을 줄이세요.
  • 디버그 빌드에서 Crashlytics 수집은 보통 비활성화합니다. 실서버에 디버그 크래시가 올라가는 걸 방지하세요.

아래처럼 교체/추가하는 것을 권장합니다.

의존성 교체:

 implementation(platform(libs.firebase.bom))
-implementation(libs.firebase.crashlytics.ndk)
+implementation("com.google.firebase:firebase-crashlytics-ktx")
 implementation(libs.firebase.analytics)

빌드타입별 수집 설정(예시):

android {
  buildTypes {
    debug {
      manifestPlaceholders["firebaseCrashlyticsCollectionEnabled"] = "false"
    }
    release {
      manifestPlaceholders["firebaseCrashlyticsCollectionEnabled"] = "true"
    }
  }
}

NDK를 실제로 사용 중이라면, 네이티브 심볼 업로드 설정도 함께 고려해 주세요.

firebaseCrashlytics {
  nativeSymbolUploadEnabled = true
}
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 119 to 121, replace the
firebase-crashlytics-ndk dependency with the standard crashlytics ktx dependency
if you do not use native NDK code (to reduce APK size and build time), and add
buildType-specific manifestPlaceholders to disable Crashlytics collection for
debug and enable for release (set firebaseCrashlyticsCollectionEnabled to
"false" for debug and "true" for release). If you do use NDK, keep the ndk
dependency but enable native symbol uploads by setting
firebaseCrashlytics.nativeSymbolUploadEnabled = true in the gradle config;
otherwise remove the ndk artifact and add
implementation(libs.firebase.crashlytics.ktx) instead.

}

// Hilt를 사용할 때 필요한 Annotation Processor
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.dagger.hilt) apply false
alias(libs.plugins.firebase.crashlytics) apply false
}
8 changes: 8 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
agp = "8.7.3"
coilCompose = "3.1.0"
converterGson = "2.11.0"
firebaseBom = "34.1.0"
hiltAndroid = "2.52"
hiltNavigationCompose = "1.2.0"
kotlin = "2.0.0"
Expand All @@ -23,6 +24,8 @@ okhttp = "4.11.0"
retrofitKotlinSerializationConverter = "1.0.0"
datastorePreferences = "1.1.3"
playServicesLocation = "21.3.0"
firebaseCrashlytics = "3.0.6"
googleServices = "4.4.3"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
Expand All @@ -31,6 +34,9 @@ coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCo
coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coilCompose" }
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coilCompose" }
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
firebase-crashlytics-ndk = { module = "com.google.firebase:firebase-crashlytics-ndk" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hiltAndroid" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
Expand Down Expand Up @@ -66,3 +72,5 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "hiltAndroid" }
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlytics" }
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices" }
Loading