ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] 프로젝트에 Android의 Hilt를 사용해보자
    Android 2024. 5. 12. 16:58
    반응형

    Hilt?

    Android에서 가장 유명한 의존성 주입 (Dependency Injection) 라이브러리입니다. 이전에 있던 Dagger를 기반으로 만들어서 사용법 및 작동 방식도 굉장히 유사한데, 원래 Dagger가 Android를 타겟으로 만든 라이브러리가 아니다보니까 환경 구축 부담 + 러닝 커브 비용 부담 때문에 쓴소리를 많이 먹었다고 합니다. 그래서 좀 더 환경을 구축하기 쉽고 이해하기도 쉬운 Koin을 사용하는 경우도 많았는데요. 그래서 구글이 Android에서 사용하기 편하라고 만든 것이 Hilt입니다. Dagger 기반으로 만들다보니까 비슷한 점도 많고 혼합해서 쓰기도 해서 그냥 Dagger Hilt라고 말하곤 합니다.

     

     

     

     

    Hilt 환경 세팅

    일단 환경 세팅을 해줍시다. 환경을 맞추지 않는다면 에러가 수두룩하게 나더라구요. 아래의 환경 세팅을 봅시다. 참고로 진행 중인 프로젝트 내의 환경 설정이라, 다른 프로젝트랑 호환이 안될 수도 있습니다. 안 되더라도 너그러히 용서해주세요.. 참고로 버전 카탈로그를 사용해서 만든 것이라 implementation(libs.hilt)implementation("com.google.dagger:hilt-android:2.44") 는 같은 것을 의미합니다.

    버전 카탈로그는 요 링크에서 확인할 수 있습니다.

    # Android Gradle Plugin Version
    8.2
    
    # gradle version
    8.2
    
    # Java
    Java 17
    
    # Compile Sdk Version
    API 34
    # libs.versions.toml
    
    [versions]
    hilt = "2.51.1"
    hiltCompiler = "1.2.0"
    androidGradlePlugin = "8.2.0"
    kotlin = "1.9.23"
    
    [libraries]
    dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
    hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
    hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltCompiler" }
    hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
    hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
    
    [plugins]
    android-application = { id = "com.android.application", version.ref = "androidGradlePlugin"}
    android-library = { id = "com.android.library", version.ref = "androidGradlePlugin"}
    kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"}
    hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
    # project/build.gradle
    
    plugins {
    	...
        alias(libs.plugins.hilt.android) apply false
    }
    # app/build.gradle
    
    plugins {
        alias(libs.plugins.android.application)
        alias(libs.plugins.kotlin.android)
        alias(libs.plugins.hilt.android)
    }
    
    apply plugin: 'com.google.dagger.hilt.android'
    apply plugin: 'kotlin-kapt'
    
    android {
        ...
        
        compileSdk 34
    
        configurations {
            implementation.exclude group: 'org.jetbrains', module: 'annotations'
        }
    
        ...
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_17
            targetCompatibility JavaVersion.VERSION_17
        }
        kotlinOptions {
            jvmTarget = '17'
        }
        packagingOptions {
            resources {
                excludes += '/META-INF/{AL2.0,LGPL2.1}'
            }
        }
    }
        
        // hilt
        implementation(libs.hilt)
        implementation(libs.hilt.compiler)
    
        // hilt testing
        implementation libs.hilt.android.testing
    
        testImplementation libs.hilt.android.testing
        testAnnotationProcessor libs.hilt.android.compiler
        kaptTest(libs.hilt.android.compiler)
    
        androidTestImplementation libs.hilt.android.testing
        kaptAndroidTest(libs.hilt.android.compiler)
        kapt (libs.dagger.hilt.compiler)

     

     

    참고 - 발생했던 여러 문제들

    error: [Hilt] Unsupported metadata version. Check that your Kotlin version is >= 1.0: java.lang.IllegalStateException

    Hilt 버전, kotlin 버전이 꼬여서 발생한 문제인데, 이걸 풀려고 해도 Gradle 버전, Java 버전이 또 꼬여서 계속 되돌임표되는 경우가 있었습니다. 각 버전을 하나씩 호환하는 버전으로 맞춰나가서 간신히 해결했습니다. (최종 버전이 위와 같습니다.)



    Duplicate class org.intellij.lang.annotations.Flow found in modules annotations-16.0.1.jar and annotations-java5-15.0.jar

    이건 그냥 hilt 뿐만 아니라 다른 세팅이랑도 꼬여서 발생한 문제인데, app/build.gradle 에 아래를 추가해서 해결했습니다.

    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }

     

     

    반응형

     

    HiltApplication 추가하기

    Hilt를 동작시키기 위해선 HiltApplication이 필수입니다. 이게 멀티 모듈 프로젝트일 경우엔 추가적으로 설명할 것이 있는데, 일단 단일 모듈 프로젝트를 기준으로 보자면 app 모듈에 아래의 파일을 추가해줍시다.

    package com.daejol.catdogcup
    
    import android.app.Application
    import dagger.hilt.android.HiltAndroidApp
    
    @HiltAndroidApp
    class HiltApplication : Application() {
        override fun onCreate() {
            super.onCreate()
        }
    }
    @HiltAndroidApp
    이것이 Hilt용 Application이다! 를 선언해주는 것입니다. 따라서 필수로 달아야하는 어노테이션입니다.

     

     

     

     

    의존성을 주입할 클래스와 모듈 생성하기

    아래의 4개 파일을 보면서 각 어노테이션에 대해 이야기해 봅시다.

    class CatImagesRepositoryImpl @Inject constructor(
        private val catImagesApi: CatImagesApi
    ) : CatImagesRepository {
        ...
    }
    interface CatImagesRepository {
        ...
    }
    @Module
    @InstallIn(SingletonComponent::class)
    abstract class RepositoryModule {
        @Singleton
        @Binds
        abstract fun bindsCatImagesRepository(
            catImagesRepositoryImpl: CatImagesRepositoryImpl
        ): CatImagesRepository
    }
    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {
        @Singleton
        @Provides
        fun provideOkHttpInterceptor(): Interceptor {
            return RetrofitInterceptor()
        }
    ...
    }
    @Inject
    이걸 단 클래스 객체를 생성할 때 생성자로 넣어준 파라미터 클래스 객체를 생성해서 주입해주겠다는 것을 의미합니다. 즉 val catImagesRepositoryImpl = CatImagesRepositoryImpl(CatImagesApi()) 를 자동으로 해주게 됩니다.

    @Module
    이 클래스를 Hilt의 주입을 위한 모듈로 사용하겠다는 것을 선언합니다. 즉 Hilt는 @Module이 달린 클래스를 보고 의존성 주입 대상이라는 것을 인식한 후, @Provides 혹은 @Binds 대상을 Hilt가 주입할 수 있게 모듈을 등록해주는 것입니다.

    @InstallIn
     어떤 형태의 컴포넌트인지 명시해 줍니다. 즉 컴포넌트 타입에 따라 주입 대상이 달라지는데, Singleton의 경우 Application 자체에 주입해서 여기저기서 다 쓸 수 있게 해주고, ActivityComponent의 경우 Activity에 주입할 수 있게 해줍니다. 주입 대상은 아래 표에서 확인할 수 있습니다.

    @Singleton
    그냥 싱글톤으로 주입을 하겠다는 것을 선언합니다.

    @Provides
    클래스를 주입할 때 사용합니다. 인터페이스를 생성할 수 없는 외부 라이브러리의 경우에도 이 어노테이션을 사용하게 됩니다. (Retrofit이나 Room 등을 주입할 때 등)

    @Binds
    인터페이스를 주입할 때 사용합니다. 그래서 실제 구현체 (Impl) 와 인터페이스를 연결한다는 의미로 Binds 라고 합니다.
    Hilt 구성요소 인젝터 대상
    SingletonComponent Application
    ActivityRetainedComponent 해당 사항 없음
    ViewModelComponent ViewModel
    ActivityComponent Activity
    FragmentComponent Fragment
    ViewComponent View
    ViewWithFragmentComponent @WithFragmentBindings 주석이 지정된 View
    ServiceComponent Service

     

     

     

     

    Activity에 의존성 주입하기

    @AndroidEntryPoint
    class MainActivity : ComponentActivity() {
        @Inject lateinit var catImagesRepository: CatImagesRepository
    
    ...
    }
    @AndroidEntryPoint
    실제 의존성을 호출해서 받아줄 EntryPoint입니다. 아래 대상들에게 해당 어노테이션을 달아서 의존성 주입을 해줄 수 있습니다.
    - Activity
    - Fragment
    - View
    - Service
    - BroadcastReceiver

    @Inject
    위에서 설명한 것과 마찬가지로 의존성을 주입할 대상입니다.

     

     

     

     

    마치며...

    사실 이 밖에도 굉장히 많은 정보와 많은 어노테이션 정보, 사용 방법 등이 있는데 여기서 다 설명하기엔 글이 너무 길어질 것 같습니다. 그래도 이미 앞서 좋은 글을 많이 작성하신 분들이 많아서 좀 더 찾아보면 큰 도움이 될 것 같습니다.

     

    참고 링크

     

    Dagger Hilt로 안드로이드 의존성 주입 시작하기

    Dagger Hilt에 대해 알아보고 안드로이드 프로젝트에 적용하는 방법을 소개합니다.

    hyperconnect.github.io

     

    Hilt를 사용한 종속 항목 삽입  |  Android 개발자  |  Android Developers

    이 페이지는 Cloud Translation API를 통해 번역되었습니다. Hilt를 사용한 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Hilt는 프로젝트에서 종속

    developer.android.com

     

     

    반응형
Designed and Written by keykat.