| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
- Android Interceptor
- 카카오 알고리즘
- 프로그래머스 알고리즘
- DataBinding
- Android 12
- MVP Architecture
- 안드로이드 갤러리 접근
- 코틀린 코루틴
- Android 12 대응
- WebView
- Android WebView
- 습관만들기
- 안드로이드 카카오 로그인
- 66챌린지
- Android
- Android Navigation
- Android ProgressBar
- 안드로이드
- Android ViewPager2
- 영어공부
- android recyclerview
- coroutine
- OkHttp Interceptor
- 알고리즘 자바
- Kotlin FCM
- 영어독립365
- scope function
- Android Jetpack
- Kotlin
- Java
- Today
- Total
나미래 Android 개발자
[Android DI] Hilt는 내부적으로 어떻게 동작할까? 본문
Hilt 내부 동작 이해하기
Annotation Processing부터 Bytecode 변조까지
Android 개발에서 의존성 주입(DI)을 본격적으로 적용하려면 가장 먼저 만나게 되는 프레임워크가 Hilt다. Hilt는 Dagger2를 기반으로 Android 환경에 최적화된 DI 솔루션이며, 복잡한 Android 컴포넌트 생명주기(Lifecycle)를 고려한 주입 방식을 표준화한다.
이번 글은 Hilt 내부 동작을 큰 흐름 중심으로 이해하는 것을 목표로 학습한 내용을 전한다. 너무 심화된 내부 구현까지 들어가기보다는, "왜 이런 구조가 필요한가?"에 집중했다.
1. Android에서 DI가 까다로운 이유
Android 환경에서 DI가 어려운 이유는 크게 두 가지다.
1). Android 컴포넌트는 개발자가 직접 생성하지 않는다
Activity, Fragment 등은 Android OS가 직접 생성하며, 개발자가 생성자나 초기화 시점을 마음대로 통제할 수 없다.
2). 컴포넌트마다 Lifecycle이 모두 다르다
Activity, Fragment, Service 그리고 Application 등 Lifecycle이 다르다.
하나의 방식으로 DI를 처리할 수 없기 때문에, 각 컴포넌트의 생성 흐름을 정확히 파악하고 주입 시점을 맞춰야 한다.
Hilt는 이 문제를 Annotation Processing + Bytecode 변조라는 조합으로 해결한다.
2. Annotation & Annotation Processing
1). Annotation 역할
Hilt의 주요 Annotation은 다음과 같다.
- @HiltAndroidApp
- @AndroidEntryPoint
- @Module
- @InstallIn
Annotation은 컴파일러와 Annotation Processor가 해석할 수 있는 메타데이터를 소스코드에 부착하는 기술이다.
Hilt는 이 메타데이터를 기반으로 DI(Factory, Component 등)를 자동 생성하낟.
2). Annotation Processing 이란
Hilt는 Annotation Processing(AP)을 통해 다음 작업을 수행한다.
- 의존성 그래프 생성 및 검증
- Dagger가 사용할 Factory, Component, Module 등의 소스코드 자동 생성
- 런타임 리플렉션 없이 컴파일 타임에 필요한 DI 구조 구성
즉, Annotation Processing은 Hilt가 동작하기 위한 DI 코드를 컴파일 전에 미리 생성하는 단계라고 볼 수 있다.
3. Hilt Bytecode 변조
Dagger는 Annotation Processing만 사용한다. 하지만 Hilt는 Android 컴포넌트에 자동으로 DI 코드를 삽입하기 위해 바이트코드 변조까지 수행한다.
왜 바이트코드 변조가 필요할까?
Annotation Processing만으로는 한계가 있다.
예를 들어, 다음 작업은 Annotation Processing으로 할 수 없다.
- 이미 존재하는 Activity/Fragment의 부모 클래스 변경
- onCreate(), onAttach() 등의 생명주기 메서드 내부에 코드 삽입
그러나 DI를 자동화하려면 다음이 필요하다.
- Activity가 생성되면 inject()가 자동으로 후출되어야 함
- Fragment도 attach 시점에 inject()가 실행되어야 함
- 개발자가 일일이 상속 구조나 주입 코드를 작성하지 않아야 함
따라서 Hilt는 컴파일된 바이트코드를 재가공하여 Android 컴포넌트의 동작을 DI 친화적으로 변경한다.
바이트코드 변조의 구체적인 예는 다음과 같다.
- MainActivity가 실제로 Hilt_MainActivity를 부모로 상속하도록 변경
- Lifecycle 내부(super.onCreate() 직전)에 inject() 호출 삽입
- 개발자가 주입 코드를 따로 작성하지 않아도 자동으로 동작
@AndroidEntryPoint
class MainActivity: AppCompatActivity()
겉으로 보기엔 이 코드가 전부지만, 실제로 바이트코드는 다음과 같은 구조로 변환되어 앱이 실행된다.
class MainActivity: Hilt_MainActivity()
그래서 Hilt_MainActivity 내부에는 이미 DI 초기화 코드가 들어있다.
4. Hilt 내부 동작 전체 흐름
정리하면 Hilt의 전체 동작 과정은 다음과 같다.
1. 개발자가 Annotation 기반 설정: @AndroidEntryPoint, @HiltAndroidApp, @Module 등
2. Annotation Processing: Dagger Component, Factory, Module 생성 및 의존성 그래프 검증
3. Kotlin/Java 컴파일: .class 바이트코드 생성
4. Hilt 바이트코드 변조: Android 컴포넌트의 부모 클래스를 Hilt_* 버전으로 교체
5. D8 변환 -> Dex 생성
6. APK/AAB 패키징
이 전체 과정이 결합되어 Annotation만 붙여도 DI가 자동으로 작동하는 개발 경험이 만들어진다.
'안드로이드 > DI' 카테고리의 다른 글
| [Android DI] Hilt 컴포넌트 계층 구조 이해하기 (0) | 2025.11.17 |
|---|
