Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

Android 최신 앱 개발: Hilt + KSP + Room + Jetpack Compose 완벽 구성 가이드 (Kotlin 2.1.20 기준)

Billcorea 2025. 5. 6. 15:53
반응형

🛠️ 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

 

반응형