🛠️ Android 최신 앱 개발: Hilt + KSP + Room + Jetpack Compose 완벽 구성 가이드 (Kotlin 2.1.20 기준)
Android 앱을 설계하면서 가장 중요한 것은 모던한 아키텍처, 선언형 UI, 의존성 주입(DI), 그리고 로컬 데이터베이스 구성입니다.
이번 포스팅에서는 Android Studio Meerkat (2024.3.1 Patch 1) 환경에서 최신 Kotlin 2.1.20을 사용해 다음 스택을 하나로 묶어 앱을 구성하는 방법을 소개합니다:
- Jetpack Compose (UI)
- Hilt (의존성 주입)
- Room (로컬 DB)
- KSP (KAPT 대체 컴파일러)
- Gradle Kotlin DSL + libs.versions.toml (버전 관리 일원화)
📌 왜 libs.versions.toml을 쓸까?
libs.versions.toml은 버전 카탈로그로, 앱에서 사용하는 라이브러리의 버전을 한 곳에 모아 관리할 수 있습니다.
덕분에 버전 충돌을 방지하고, 여러 모듈 간 일관성을 유지하며, 버전 변경 시도 매우 쉬워집니다.
예: gradle/libs.versions.toml
[versions]
kotlin = "2.1.20"
agp = "8.4.0"
ksp = "2.1.20-1.0.20"
compose-bom = "2024.05.00"
compose-compiler = "1.5.14"
hilt = "2.51.1"
room = "2.6.1"
[libraries]
# Compose UI
compose-ui = { module = "androidx.compose.ui:ui" } # Compose UI 핵심
compose-material3 = { module = "androidx.compose.material3:material3" } # Material Design 3
compose-tooling = { module = "androidx.compose.ui:ui-tooling" } # Compose 디버깅/프리뷰
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
# Android 필수
core-ktx = { module = "androidx.core:core-ktx", version = "1.13.1" } # Kotlin 표준 확장
activity-compose = { module = "androidx.activity:activity-compose", version = "1.9.0" } # Compose용 Activity
# Hilt DI
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } # DI 핵심
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } # KSP 애노테이션 처리기
# Room DB
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } # 런타임
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } # Coroutine 연동
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } # KSP 처리기
⚙️ 앱 모듈 설정 (build.gradle.kts)
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.hilt.android)
alias(libs.plugins.ksp) // KAPT 대신 KSP 사용
}
android {
compileSdk = 36
namespace = "com.example.hiltksp"
defaultConfig {
applicationId = "com.example.hiltksp"
minSdk = 24
targetSdk = 36
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose-compiler.get()
}
kotlinOptions {
jvmTarget = "17"
}
ksp {
useKsp2 = false // 아직까지는 ksp2 에 버그가 있는 것으로 보임.
}
}
dependencies {
// Compose
implementation(platform(libs.compose.bom))
implementation(libs.compose.ui)
implementation(libs.compose.material3)
debugImplementation(libs.compose.tooling)
// Core
implementation(libs.core.ktx)
implementation(libs.activity.compose)
// Hilt + KSP
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
// Room + KSP
implementation(libs.room.runtime)
implementation(libs.room.ktx)
ksp(libs.room.compiler)
}
*** KSP2 에서는 빌드시 현재(2025.04.20 기준)까지는 오류가 있는 것 같아서 useKsp2 = false 설정해 빌드를 시도 했습니다.
🚀 Hilt 설정
1. Application 클래스
@HiltAndroidApp
class MyApp : Application()
<!-- AndroidManifest.xml -->
<application android:name=".MyApp" ... />
2. DI 모듈 예시
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideSampleMessage(): String = "Hello from Hilt!"
}
💾 Room 설정
1. Entity
@Entity(tableName = "notes")
data class Note(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val content: String
)
2. DAO
@Dao
interface NoteDao {
@Query("SELECT * FROM notes")
suspend fun getAll(): List<Note>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(note: Note)
@Delete
suspend fun delete(note: Note)
}
3. Database
@Dao
interface NoteDao {
@Query("SELECT * FROM notes")
suspend fun getAll(): List<Note>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(note: Note)
@Delete
suspend fun delete(note: Note)
}
4. DatabaseModule
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "app_db").build()
}
@Provides
fun provideNoteDao(db: AppDatabase): NoteDao = db.noteDao()
}
🧠 ViewModel + Compose 연동
ViewModel
@HiltViewModel
class NoteViewModel @Inject constructor(
private val dao: NoteDao
) : ViewModel() {
private val _notes = mutableStateListOf<Note>()
val notes: List<Note> = _notes
fun loadNotes() {
viewModelScope.launch {
_notes.clear()
_notes.addAll(dao.getAll())
}
}
fun addNote(content: String) {
viewModelScope.launch {
dao.insert(Note(content = content))
loadNotes()
}
}
}
MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val viewModel: NoteViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.loadNotes()
setContent {
Column {
Button(onClick = { viewModel.addNote("Test Note") }) {
Text("Add Note")
}
LazyColumn {
items(viewModel.notes) { note ->
Text(note.content)
}
}
}
}
}
}
✅ 마무리 정리
- Kotlin 2.1.20 기반의 최신 Android 프로젝트
- Hilt + KSP로 DI 구성 (kapt 없이!)
- Room도 KSP로 설정하여 컴파일 속도 향상
- Compose를 통한 선언적 UI 개발
- libs.versions.toml을 활용한 깔끔한 버전 관리
⏭️ 다음에 할 수 있는 것들
- Repository 패턴으로 ViewModel과 DB 분리
- Navigation Compose로 여러 화면 구성
- 테스트 코드 추가 (FakeDao, HiltTestRule 등)
- GitHub에 템플릿으로 공유
필요하다면 이 구성을 기반으로 한 GitHub 프로젝트 템플릿도 만들어드릴 수 있어요.
"완성된 예제를 보고 따라하고 싶다"면 알려주세요! 😊 전체 프로젝트는 아래 링크에 있습니다. 😊
nari4169/Hilt_Room_Example_Project: project default example
GitHub - nari4169/Hilt_Room_Example_Project: project default example
project default example. Contribute to nari4169/Hilt_Room_Example_Project development by creating an account on GitHub.
github.com
'모바일 앱(안드로이드)' 카테고리의 다른 글
Android 헬스 커넥트 시작하기: 통합 및 권한 관리 가이드 (0) | 2025.05.08 |
---|---|
제트팩 구성에서 스크롤 효과가 있는 무너지는 앱바 생성 ... 퍼옴 (1) | 2025.04.18 |
트윌리오 SMS를 이용한 안드로이드 앱 전화번호 검증 ... 퍼옴 (1) | 2025.04.14 |
Android Studio Meerkat | 2024.3.1 Patch 1 ... 퍼옴 (1) | 2025.03.29 |
MITM(Man-in-the-Middle) 공격에 맞서 안드로이드 앱 확보 ... 퍼옴 (2) | 2025.03.19 |