안드로이드 ProGuard 완벽 가이드: 소스코드 난독화를 위한 모든 것
안녕하세요! 오늘은 안드로이드 앱 개발자라면 꼭 알아야 할 ProGuard에 대해 자세히 알아보겠습니다. 앱의 보안을 강화하고 크기를 최적화하는 데 필수적인 ProGuard의 모든 것, 특히 중요 파일 목록과 그 내용을 쉽게 이해할 수 있도록 설명해 드리겠습니다.

목차
- ProGuard란 무엇인가?
- ProGuard의 주요 기능
- ProGuard 설정 방법
- 중요 ProGuard 파일 목록과 설명
- proguard-rules.pro 파일 작성 가이드
- 라이브러리별 ProGuard 규칙
- ProGuard 사용 시 주의사항
- 문제 해결 가이드
- R8과 ProGuard의 차이점
- 자주 묻는 질문
#1. ProGuard란 무엇인가?
ProGuard는 안드로이드 앱의 자바 바이트코드를 최적화하고 난독화하는 도구입니다. 구글이 안드로이드 스튜디오에 기본으로 통합한 이 도구는 앱의 보안을 강화하고 용량을 줄이는 데 큰 역할을 합니다.

ProGuard가 필요한 이유
- 리버스 엔지니어링 방지: 앱의 코드를 분석하기 어렵게 만들어 지적 재산을 보호합니다.
- 앱 크기 감소: 사용하지 않는 코드를 제거하고 클래스, 필드, 메서드의 이름을 짧게 바꿔 APK 크기를 줄입니다.
- 성능 최적화: 불필요한 코드를 제거하고 최적화하여 앱 성능이 향상됩니다.
- DEX 65K 메소드 제한 문제 해결: 안드로이드의 DEX 파일 형식 제한을 해결하는 데 도움을 줍니다.
#2. ProGuard의 주요 기능
ProGuard는 크게 네 가지 주요 기능을 제공합니다:
1. 축소(Shrinking)
- 사용하지 않는 클래스, 필드, 메서드를 감지하고 제거합니다.
- 코드베이스를 정리하여 APK 크기를 줄입니다.
2. 최적화(Optimization)
- 바이트코드를 분석하고 최적화합니다.
- 사용되지 않는 코드 블록 제거, 메서드 인라이닝, 상수 계산 등을 수행합니다.
3. 난독화(Obfuscation)
- 클래스, 필드, 메서드의 이름을 의미 없는 짧은 이름으로 바꿉니다.
- 디컴파일된 코드를 이해하기 어렵게 만들어 리버스 엔지니어링을 방지합니다.
4. 사전 검증(Preverification)
- 자바 바이트코드를 JVM이나 안드로이드 런타임에 로드하기 전에 미리 검증합니다.
- 런타임 오버헤드를 줄입니다.
#3. ProGuard 설정 방법
안드로이드 스튜디오에서 ProGuard를 설정하는 방법을 단계별로 알아보겠습니다.
build.gradle 파일 설정
앱 수준의 build.gradle
파일에서 다음과 같이 ProGuard를 활성화할 수 있습니다:
android {
buildTypes {
release {
minifyEnabled true // 코드 축소, 난독화, 최적화 활성화
shrinkResources true // 사용하지 않는 리소스 제거
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
// 디버그 빌드에서도 활성화하려면 (선택사항)
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
주요 설정 옵션
minifyEnabled
: 코드 축소, 최적화, 난독화를 활성화합니다.shrinkResources
: 사용하지 않는 리소스를 제거합니다 (minifyEnabled가 true일 때만 작동).proguardFiles
: ProGuard 규칙이 담긴 파일을 지정합니다.
#4. 중요 ProGuard 파일 목록과 설명
안드로이드 ProGuard 설정에서 알아야 할 중요한 파일들을 살펴보겠습니다.
1. proguard-android.txt
- 위치:
<ANDROID_SDK>/tools/proguard/proguard-android.txt
- 설명: 안드로이드 SDK에서 제공하는 기본 ProGuard 설정 파일입니다.
- 내용: 안드로이드 프레임워크 관련 기본 keep 규칙이 포함되어 있습니다.
- 사용:
getDefaultProguardFile('proguard-android.txt')
로 참조합니다.
2. proguard-android-optimize.txt
- 위치:
<ANDROID_SDK>/tools/proguard/proguard-android-optimize.txt
- 설명: 코드 최적화가 추가된 향상된 버전의 기본 설정 파일입니다.
- 내용:
proguard-android.txt
의 모든 규칙 + 추가 최적화 옵션이 포함됩니다. - 사용:
getDefaultProguardFile('proguard-android-optimize.txt')
로 참조합니다. - 특징: 기본 파일보다 더 적극적인 최적화를 수행합니다.
3. proguard-rules.pro
- 위치: 앱 모듈의 루트 디렉토리 (
app/proguard-rules.pro
) - 설명: 앱 특정 ProGuard 규칙을 정의하는 사용자 정의 파일입니다.
- 내용: 라이브러리 관련 규칙, 커스텀 클래스 유지 규칙 등을 정의합니다.
- 편집 방법: 안드로이드 스튜디오에서 직접 편집할 수 있습니다.
4. proguard-project.txt (이전 버전)
- 위치: 프로젝트 루트 디렉토리
- 설명: 이전 안드로이드 빌드 시스템에서 사용하던 파일입니다.
- 현재 상태: 최신 안드로이드 스튜디오에서는 사용되지 않습니다.
5. mapping.txt
- 위치:
app/build/outputs/mapping/release/
- 설명: 난독화 과정에서 생성된 이름 매핑 정보가 포함된 파일입니다.
- 중요성: 난독화된 스택 트레이스를 원래 이름으로 복원하는 데 필수적입니다.
- 관리 방법: 각 릴리스 버전마다 따로 보관해야 합니다.
6. seeds.txt
- 위치:
app/build/outputs/mapping/release/
- 설명: 난독화되지 않고 유지된 클래스와 멤버의 목록입니다.
- 용도: 어떤 클래스와 멤버가 entry point로서 보존되었는지 확인할 수 있습니다.
7. usage.txt
- 위치:
app/build/outputs/mapping/release/
- 설명: 앱에서 사용된 코드와, 미사용으로 제거된 코드의 목록입니다.
- 용도: 어떤 코드가 제거되었는지 확인하고 문제를 진단할 때 유용합니다.
8. dump.txt
- 위치:
app/build/outputs/mapping/release/
- 설명: 앱의 내부 구조에 대한 상세 정보를 포함합니다.
- 내용: 모든 클래스 파일의 내부 구조를 텍스트로 표현합니다.
- 용도: 고급 디버깅과 문제 해결에 사용됩니다.
#5. proguard-rules.pro 파일 작성 가이드
proguard-rules.pro
파일은 앱 특성에 맞게 사용자가 직접 작성하는 파일입니다. 다음은 이 파일에 포함될 수 있는 주요 규칙들입니다.
기본 템플릿
# 기본 ProGuard 규칙
-keepattributes Signature
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
# 앱 모델 클래스 (예: JSON 파싱용 POJO)
-keep class com.example.app.model.** { *; }
# Android 컴포넌트
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.view.View
# 네이티브 메소드
-keepclasseswithmembernames class * {
native <methods>;
}
# Enum 클래스 보존
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Parcelable 구현체
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
# R 클래스의 정적 필드
-keepclassmembers class **.R$* {
public static <fields>;
}
주요 ProGuard 지시어
- -keep: 지정된 클래스와 멤버를 그대로 유지합니다.
- -keepclassmembers: 지정된 클래스의 멤버만 유지합니다.
- -keepclasseswithmembers: 지정된 멤버를 포함하는 클래스를 유지합니다.
- -keepnames: 지정된 클래스와 멤버의 이름을 유지합니다(축소는 적용).
- -keepclassmembernames: 지정된 클래스 멤버의 이름을 유지합니다.
- -dontwarn: 지정된 클래스에 대한 경고를 무시합니다.
- -assumenosideeffects: 지정된 메소드 호출을 제거합니다(로그 제거 등에 유용).
주요 와일드카드와 필터
*
: 모든 패키지 이름, 클래스 이름 또는 메소드 이름과 일치**
: 모든 패키지와 하위 패키지와 일치***
: 모든 타입(매개변수 타입이나 반환 타입)과 일치!
: 부정(예:!android.**
는 android 패키지를 제외)<init>
: 생성자<fields>
: 모든 필드<methods>
: 모든 메소드
#6. 라이브러리별 ProGuard 규칙
많은 안드로이드 라이브러리는 특정 ProGuard 규칙이 필요합니다. 다음은 자주 사용되는 라이브러리의 ProGuard 규칙 예시입니다.
Retrofit 2
# Retrofit
-keepattributes Signature
-keepattributes Exceptions
-keep class retrofit2.** { *; }
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-dontwarn retrofit2.**
Gson
# Gson
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
OkHttp 3
# OkHttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
Glide
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
Firebase
# Firebase
-keep class com.google.firebase.** { *; }
-keep class com.firebase.** { *; }
-keep class org.apache.** { *; }
-keepnames class com.fasterxml.jackson.** { *; }
-keepnames class javax.servlet.** { *; }
-keepnames class org.ietf.jgss.** { *; }
-dontwarn org.apache.**
-dontwarn org.w3c.dom.**
Kotlin Serialization
# Kotlin Serialization
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt
-keep,includedescriptorclasses class com.yourcompany.yourpackage.**$$serializer { *; }
-keepclassmembers class com.yourcompany.yourpackage.** {
*** Companion;
}
-keepclasseswithmembers class com.yourcompany.yourpackage.** {
kotlinx.serialization.KSerializer serializer(...);
}
#7. ProGuard 사용 시 주의사항
ProGuard를 사용할 때 알아두어야 할 중요한 주의사항들입니다.
1. 리플렉션 사용 시 주의
자바 리플렉션을 사용하는 코드는 ProGuard로 인해 문제가 발생할 수 있습니다. 리플렉션을 통해 접근하는 클래스와 멤버는 명시적으로 유지해야 합니다.
-keep class com.example.app.ReflectedClass { *; }
2. 시리얼라이제이션/디시리얼라이제이션
JSON 파싱 등에 사용되는 모델 클래스는 보통 유지해야 합니다.
-keep class com.example.app.model.** { *; }
3. JavaScript 인터페이스
WebView에서 자바스크립트 인터페이스로 사용되는 클래스는 유지해야 합니다.
-keepclassmembers class com.example.app.JavaScriptInterface {
<methods>;
}
4. 네이티브 메소드
JNI를 통해 호출되는 네이티브 메소드는 이름이 변경되면 안 됩니다.
-keepclasseswithmembernames class * {
native <methods>;
}
5. 커스텀 뷰
XML 레이아웃에서 참조하는 커스텀 뷰 클래스는 유지해야 합니다.
-keep public class com.example.app.CustomView { *; }
6. 라이브러리 누락 경고
사용하지 않는 라이브러리 클래스에 대한 경고는 -dontwarn
으로 무시할 수 있습니다.
-dontwarn okio.**
-dontwarn retrofit2.**
#8. 문제 해결 가이드
ProGuard를 적용한 후 발생할 수 있는 일반적인 문제와 해결 방법을 알아보겠습니다.
1. ClassNotFoundException / NoClassDefFoundError
원인: ProGuard가 필요한 클래스를 제거했거나 난독화했습니다.
해결 방법:
-keep class com.example.app.MissingClass { *; }
2. IllegalArgumentException: No enum constant
원인: Enum 클래스가 올바르게 유지되지 않았습니다.
해결 방법:
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
3. 크래시 로그 해독하기
난독화된 앱에서 크래시가 발생하면 스택 트레이스도 난독화됩니다. mapping.txt
파일을 사용하여 원래 클래스 및 메소드 이름으로 복원할 수 있습니다.
Firebase Crashlytics 설정:
android {
buildTypes {
release {
firebaseCrashlytics {
mappingFileUploadEnabled true
}
}
}
}
Android Studio Retrace 도구 사용:
mapping.txt
파일을 준비합니다.- Logcat에서 난독화된 스택 트레이스를 복사합니다.
- Android Studio의 "Analyze > Analyze Stack Trace" 메뉴를 사용합니다.
- mapping.txt 파일과 스택 트레이스를 붙여넣고 분석합니다.
4. 디버그 빌드에서는 동작하지만 릴리스 빌드에서 문제가 발생할 때
릴리스 빌드에서 ProGuard 문제를 디버깅하려면:
- 릴리스 빌드를 로컬에서 실행하여 문제를 재현합니다.
- 로그를 확인하여 어떤 클래스나 메소드가 문제인지 파악합니다.
usage.txt
파일을 확인하여 제거된 코드를 확인합니다.- 필요한 클래스를 유지하는 규칙을 추가합니다.
#9. R8과 ProGuard의 차이점
안드로이드 스튜디오 3.4부터는 기본적으로 ProGuard 대신 R8 컴파일러가 사용됩니다.
R8이란?
R8은 구글이 개발한 코드 축소 및 난독화 도구로, ProGuard를 대체하기 위해 설계되었습니다. ProGuard보다 빠르고 효율적이며, 더 공격적인 최적화를 제공합니다.
주요 차이점
- 속도: R8이 ProGuard보다 빠르게 처리합니다.
- 코드 크기: R8은 일반적으로 더 작은 APK를 생성합니다.
- 호환성: R8은 ProGuard 규칙과 호환됩니다.
- 최적화: R8은 더 적극적인 최적화 기법을 사용합니다.
- 통합: R8은 D8 DEX 컴파일러와 함께 작동하도록 설계되었습니다.
R8 사용 설정/해제
gradle.properties
파일에서 R8 사용을 제어할 수 있습니다:
# R8 사용 (기본값)
android.enableR8=true
# ProGuard 사용 (R8 비활성화)
android.enableR8=false
#10. 자주 묻는 질문
Q: ProGuard를 적용하면 앱 성능이 향상되나요?
A: 예, ProGuard는 코드를 최적화하고 불필요한 코드를 제거하여 앱의 실행 속도를 향상시킬 수 있습니다. 또한 APK 크기가 작아져 설치 시간과 메모리 사용량이 줄어듭니다.
Q: ProGuard는 앱을 100% 안전하게 보호할 수 있나요?
A: 아니요, ProGuard는 리버스 엔지니어링을 어렵게 만들지만 완전히 막지는 못합니다. 숙련된 분석가는 여전히 난독화된 코드를 분석할 수 있습니다. 중요한 알고리즘이나 키는 서버 측에 두거나 추가 보안 계층을 사용하는 것이 좋습니다.
Q: 모든 빌드에 ProGuard를 적용해야 하나요?
A: 아니요, 일반적으로 릴리스 빌드에만 적용합니다. 디버그 빌드에 적용하면 디버깅이 어려워질 수 있습니다. 하지만 릴리스 전에 ProGuard가 적용된 빌드를 테스트하는 것은 중요합니다.
Q: mapping.txt 파일을 왜 보관해야 하나요?
A: mapping.txt 파일은 난독화된 클래스 이름을 원래 이름으로 매핑해주는 정보를 담고 있습니다. 사용자로부터 받은 크래시 리포트를 분석하려면 해당 버전의 mapping.txt 파일이 필요합니다.
Q: ProGuard 규칙을 어디서 찾을 수 있나요?
A: 많은 인기 라이브러리는 공식 문서나 GitHub 저장소에 ProGuard 규칙을 제공합니다. 또한 proguard-rules-examples 같은 저장소에서 일반적인 라이브러리의 규칙을 찾을 수 있습니다.
결론
ProGuard는 안드로이드 앱의 보안과 성능을 향상시키는 강력한 도구입니다. 적절한 설정과 규칙을 통해 앱을 효과적으로 보호하고 최적화할 수 있습니다.
이 가이드에서는 ProGuard의 기본 개념부터 중요 파일, 설정 방법, 문제 해결까지 모든 내용을 다뤘습니다. 이제 여러분의 안드로이드 앱에 ProGuard를 적용하여 더 안전하고 효율적인 앱을 만들어 보세요!
긴 글 읽어주셔서 감사합니다.
끝.
'■Development■ > 《Android》' 카테고리의 다른 글
[Android] App Architecture 가이드 2 (0) | 2019.09.23 |
---|---|
[Android] App Architecture 가이드 1 (0) | 2019.09.23 |
[Android] Button의 텍스트에 밑줄을 추가하는 5가지 완벽 (0) | 2019.09.22 |
[Android] Android ABI 완벽 가이드 : 초보 개발자를 위한 적용 및 관리 방법 (0) | 2019.09.22 |
[Android] Touch 이벤트 완벽 가이드: 발생 순서부터 처리 방법까지 (0) | 2019.09.10 |