Running Tracker๋ ์ฌ์ฉ์์ ๋ฌ๋ ํ๋์ ๊ธฐ๋กํ๊ณ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์๋
์๋๋ก์ด๋ ๋ฌ๋ ํธ๋์ปค ์ ํ๋ฆฌ์ผ์ด์
์
๋๋ค.
Kotlin๊ณผ Jetpack Compose๋ฅผ ๊ธฐ๋ฐ์ผ๋ก MVVM ์ํคํ
์ฒ๋ฅผ ์ ์ฉํด ๊ฐ๋ฐ๋์์ต๋๋ค.
๋ฌ๋ ์ค ๊ฒฝ๊ณผ ์๊ฐ๊ณผ ์ด๋ ๊ฒฝ๋ก๋ฅผ ์ค์๊ฐ์ผ๋ก ํ์ธํ ์ ์์ผ๋ฉฐ,
๋จ์ํ๊ณ ์ง๊ด์ ์ธ UI๋ฅผ ๋ชฉํ๋ก ์ค๊ณ๋์์ต๋๋ค.
-
๋ฌ๋ ํ์ด๋จธ
- ViewModel์์ ์ง์ ๊ด๋ฆฌ๋๋ ์ฝ๋ฃจํด ๊ธฐ๋ฐ ํ์ด๋จธ
- Start / Pause / Stop ๋์ ๋ถ๋ฆฌ
- Pause ํ Start ์ ์๊ฐ ์ ์ง, Stop ์์๋ง ์ด๊ธฐํ
-
์ค์๊ฐ ์์น ๊ฒฝ๋ก ํ์
- Google Maps Compose๋ฅผ ํ์ฉํ ๋ฌ๋ ๊ฒฝ๋ก ์๊ฐํ
- ๋ฌ๋ ์ค ์ด๋ํ ๊ฒฝ๋ก๋ฅผ Polyline์ผ๋ก ์ง๋์ ํ์
-
์ํ ๊ธฐ๋ฐ UI
- UI๋ ViewModel์
StateFlow๋ง ๊ตฌ๋ - ๋น์ฆ๋์ค ๋ก์ง๊ณผ UI ๋ก์ง์ ๋ช ํํ ๋ถ๋ฆฌ
- UI๋ ViewModel์
-
์์กด์ฑ ์ฃผ์
- Koin์ ํ์ฉํ ViewModel ๋ฐ ์์น ํด๋ผ์ด์ธํธ ์ฃผ์
- ํ ์คํธ ๋ฐ ํ์ฅ์ ์ฉ์ดํ ๊ตฌ์กฐ
- Language: Kotlin
- UI: Jetpack Compose (Material3)
- Architecture: MVVM
- State Management: StateFlow
- Asynchronous: Kotlin Coroutines
- Dependency Injection: Koin
- Maps: Google Maps Compose
- Location: FusedLocationProviderClient
- Android Studio (์ต์ ์์ ๋ฒ์ ๊ถ์ฅ)
- JDK 17 (Android Studio ๋ด์ฅ JDK ์ฌ์ฉ ๊ฐ๋ฅ)
- Google Maps API Key
git clone <repo-url>
cd RunningTrackerapp/src/main/res/values/google_maps_key.xml ํ์ผ์ ์์ฑํ๊ณ ์๋ ๋ด์ฉ์ ์ถ๊ฐํ์ธ์.
<resources>
<string name="google_maps_key" translatable="false">YOUR_API_KEY</string>
</resources>์ถ์ ๊ธฐ์ค ๊ถ์ฅ ์ค์ :
- ๋๋ฒ๊ทธ/๋ฆด๋ฆฌ์ค API ํค๋ฅผ ๋ถ๋ฆฌํด์ ์ฌ์ฉ
- Google Cloud Console์์
Maps SDK for Androidํ์ฑํ - API ํค ์ ํ(Application restrictions) ์ค์ :
- Android apps
- ํจํค์ง๋ช
:
com.example.runningtracker - SHA-1 ์ธ์ฆ์ ์ง๋ฌธ: ๋๋ฒ๊ทธ/๋ฆด๋ฆฌ์ค ๊ฐ๊ฐ ๋ฑ๋ก
- API restrictions์์ Maps ๊ด๋ จ API๋ง ํ์ฉ
์ฐธ๊ณ :
google_maps_key.xml์.gitignore์ ํฌํจ๋์ด ์์ผ๋ฏ๋ก ์ ์ฅ์์ ์ปค๋ฐ๋์ง ์์ต๋๋ค.- ๋ฆด๋ฆฌ์ค ๋น๋ ์ ์ค์ ๋ฆด๋ฆฌ์ค keystore ๊ธฐ์ค SHA-1๋ก ๋์ ํ์ธ์ด ํ์ํฉ๋๋ค.
- Android Studio์์ ํ๋ก์ ํธ๋ฅผ ์ฐ ๋ค ์๋ฎฌ๋ ์ดํฐ ๋๋ ์ค์ ๊ธฐ๊ธฐ์์ ์คํ
- ๋๋ ํฐ๋ฏธ๋์์ ๋๋ฒ๊ทธ ๋น๋:
./gradlew assembleDebugWindows:
gradlew.bat assembleDebugACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION: ๋ฌ๋ ์ค ์์น ์ถ์ ๋ฐ ๊ฒฝ๋ก ํ์FOREGROUND_SERVICE,FOREGROUND_SERVICE_LOCATION: ๋ฌ๋ ์ค ๋ฐฑ๊ทธ๋ผ์ด๋ ์์น ์ถ์ ์ ์งPOST_NOTIFICATIONS(Android 13+): ํฌ๊ทธ๋ผ์ด๋ ์๋น์ค ์๋ฆผ ํ์
- ๋ฌ๋ ๊ธฐ๋ก: ์์ ์๊ฐ, ์ด ์ด๋ ์๊ฐ, ํ๊ท ์๋, ์ด๋ ๊ฑฐ๋ฆฌ
- ์์น ๋ฐ์ดํฐ: ๋ฌ๋ ๊ฒฝ๋ก ํ์๋ฅผ ์ํด ์ค์๊ฐ ์ฌ์ฉ
- ์ ์ฅ ์์น: ๊ธฐ๊ธฐ ๋ด๋ถ Room DB (
running_database)
- ๋ณ๋ ๋ฐฑ์๋ ์๋ฒ๋ก ๋ฌ๋ ๊ธฐ๋ก์ ์ ์กํ์ง ์์
- Google Maps SDK ์ฌ์ฉ์ผ๋ก ์ง๋ ํ์ ๊ด๋ จ ๋คํธ์ํฌ ํต์ ์ด ๋ฐ์ํ ์ ์์
- ์์น ๊ถํ์ด ์์ผ๋ฉด ์์น ๊ธฐ๋ฐ ๊ธฐ๋ฅ์ด ๋์ํ์ง ์์
- ๊ถํ์ ๊ธฐ๊ธฐ ์ค์ ์์ ์ธ์ ๋ ๋ณ๊ฒฝ ๊ฐ๋ฅ
์ค์ ์คํ ์ด ์ถ์ ์์๋ ๋ณ๋์ Privacy Policy ๋ฌธ์(URL)์ Play Console ๋ฐ์ดํฐ ๋ณด์ ์์ ๋ด์ฉ์ ๋ณธ ์น์ ๊ณผ ์ผ์น์ํค์ธ์.
- ์ ์ฑ
URL:
https://example.com/running-tracker/privacy - ์ถ์ ์ ์ URL์ ์ค์ ๊ณต๊ฐ ๋ฌธ์ ์ฃผ์๋ก ๊ต์ฒดํ์ธ์.
- ์ฑ ๋ด ์ค์ ํ๋ฉด/์จ๋ณด๋ฉ, Play Store ๋ฑ๋ก ์ ๋ณด(๊ฐ์ธ์ ๋ณด์ฒ๋ฆฌ๋ฐฉ์นจ)์ ๋์ผํ URL์ ์ฌ์ฉํ์ธ์.
minSdk: 24 (Android 7.0)targetSdk: 36compileSdk: 36- ์ธ์ด/๋ฐํ์: Kotlin + JVM 11 ํ๊ฒ
์คํ ์๊ตฌ์ฌํญ:
- ์์น ์๋น์ค(GPS) ์ฌ์ฉ ๊ฐ๋ฅ ๊ธฐ๊ธฐ
- ์ง๋ ๋ก๋ฉ ๋ฐ ์์น ์ฒ๋ฆฌ ์ ๋คํธ์ํฌ ์ฐ๊ฒฐ ๊ถ์ฅ
๊ฒ์ฆ ๊ถ์ฅ ๋ฒ์(์ถ์ ์ ):
- Android 7/8/10/13 ์ด์ ๋ฒ์ ๋ณ ๊ธฐ๋ณธ ๋์ ์ ๊ฒ
- ๊ถํ ๊ฑฐ๋ถ/์ฌํ์ฉ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ํ, ๋ฐฐํฐ๋ฆฌ ์ ์ ๋ชจ๋ ์๋๋ฆฌ์ค ์ ๊ฒ
ํ์ฌ ์ค์ ๊ธฐ์ค:
release๋น๋ ํ์ ์กด์ฌ- ์ฝ๋ ์ถ์/๋๋
ํ:
isMinifyEnabled = false - Google Maps API ํค๋ ๋ฆด๋ฆฌ์ค ํค(SHA-1) ๊ธฐ์ค์ผ๋ก ๋ณ๋ ๊ฒ์ฆ ํ์
๋น๋ ๋ช ๋ น:
./gradlew bundleReleaseWindows:
gradlew.bat bundleRelease์ถ๋ ฅ ๊ฒฝ๋ก:
app/build/outputs/bundle/release/
์คํ ์ด ๋ฐฐํฌ ์ ํ์ ์ฒดํฌ:
- ์ ๋ก๋์ฉ ์๋ช ํค(keystore)๋ก ์๋ช ๋ AAB ์์ฑ
versionCode/versionName์ ๋ฐ์ดํธ- ๋ฆด๋ฆฌ์ค ๋น๋์์ ์ง๋/์์น/์๋ฆผ ๊ถํ ํ๋ฆ ์ต์ข ์ ๊ฒ
- ProGuard/R8 ์ ์ฉ ๊ณํ์ด ์๋ค๋ฉด ๋๋ ํ ํ ํ๊ท ํ ์คํธ ์ํ
app/
โโ presentation/
โ โโ running/
โ โ โโ RunningScreen.kt
โ โ โโ RunningViewModel.kt
โ โ โโ RunningUiState.kt
โ โโ ButtonControls.kt
โ โโ RunningMap.kt
โโ location/
โ โโ LocationClient.kt
โโ di/
โ โโ appModule.kt
โโ util/
โโ TimeFormatter.kt
| ์ด๊ธฐ ํ๋ฉด | ๋ฌ๋ ์์ |
|---|---|
![]() |
![]() |
| ์ผ์์ ์ง | ๋ฌ๋ ๊ธฐ๋ก |
|---|---|
![]() |
![]() |
์๋น์ค ์ฝ๋ ๋ณต์ก๋๋ฅผ ์ค์ด๊ธฐ ์ํด ํต์ฌ ๋ก์ง์ ์ญํ ๋จ์๋ก ๋ถ๋ฆฌํ์ต๋๋ค.
-
RunTimer
-
์๊ฐ ์ธก์ ์ ์ฉ ์ปดํฌ๋ํธ
-
์ฝ๋ฃจํด ๊ธฐ๋ฐ, ์์ ๋น์ฆ๋์ค ๋ก์ง
-
-
RunLocationTracker
-
์์น ์์ง ์ ์ฉ ์ปดํฌ๋ํธ
-
LocationClient๋ฅผ ํตํด Flow ๊ธฐ๋ฐ ์์น ์คํธ๋ฆผ ์ฒ๋ฆฌ
-
RunningService
โโ RunTimer (์๊ฐ ์ธก์ )
โโ RunLocationTracker (์์น ์์ง)
- ์๋น์ค๋ ์ค์ผ์คํธ๋ ์ด์ ์ญํ ๋ง ๋ด๋นํ๋๋ก ์ ๋ฆฌ
- ํ ์คํธ ๋ฐ ์ ์ง๋ณด์ ์ฉ์ด์ฑ ํฅ์
-
BroadcastReceiver ๊ธฐ๋ฐ ๋ฐฐํฐ๋ฆฌ ์ํ ๊ฐ์ง
-
Android ์์คํ ๋ธ๋ก๋์บ์คํธ(ACTION_BATTERY_CHANGED) ํ์ฉ
๋์ ๊ท์น:
๋ฌ๋ ์์ ์
- ๋ฐฐํฐ๋ฆฌ 30% ์ดํ โ ๊ฒฝ๊ณ ๋ฉ์์ง ํ์ (์ด๋์ ์์ ๊ฐ๋ฅ)
๋ฌ๋ ์ค
- ๋ฐฐํฐ๋ฆฌ 20% ์ดํ โ ์๋์ผ๋ก ๋ฌ๋ ์ข ๋ฃ + ๊ธฐ๋ก ์ ์ฅ
์ฌ์ฉ์ ๊ฒฝํ์ ํด์น์ง ์์ผ๋ฉด์ ์์ ์ฑ ํ๋ณด
-
Robolectric + coroutines-test ๊ธฐ๋ฐ ๋จ์ ํ ์คํธ ์์ฑ
-
Android ์์กด์ฑ์ด ์๋ ํต์ฌ ๋ก์ง ์์ฃผ๋ก ํ ์คํธ
ํ ์คํธ ๋์: RunTimer
-
start / pause / stop ๋์ ๊ฒ์ฆ
-
์๊ฐ ์ฆ๊ฐ ๋ฐ ์ด๊ธฐํ ๋ก์ง ํ์ธ



