R8로 Unreal Engine 코드 축소 및 최적화

Unreal Engine의 핵심 게임 로직은 C++ 또는 Blueprints로 작성되지만 Android 패키징은 Java 및 Kotlin 바이트코드 (classes.dex)를 컴파일하여 GameActivity 수명 주기 이벤트, Google Play 서비스, 결제, 오디오, 분석 플러그인을 처리합니다.

Android Gradle 플러그인(AGP)의 기본 코드 축소기 및 최적화 도구인 R8은 사용되지 않는 클래스와 메서드를 삭제하고 바이트 코드를 최적화합니다. 이렇게 하면 패키지 다운로드 크기가 줄어들 뿐만 아니라 메모리 매핑 (mmap) DEX 페이지의 런타임 메모리 사용량과 기준 Java 프로세스 오버헤드가 줄어들어 실제 메모리 압박과 로우 메모리 킬러 (LMK) 종료가 완화됩니다. Google Play는 Android vitals의 DEX 코드 최적화 측정항목을 통해 게임의 DEX 최적화 수준도 모니터링합니다.

기본 동작 및 언리얼 엔진 버전 지원

UE 4.22.0부터 Unreal Engine의 UEDeployAndroid.cs는 기본적으로 생성된 Android 출시 빌드 구성(buildAdditions.gradle)에 minifyEnabled true를 삽입합니다. UE 4.25에서 번들 도구 모음을 AGP 4.0.0으로 업그레이드했기 때문에 UE 4.25 이상의 모든 출시 (배송 및 배포) 빌드에서 추가 설정 없이 R8이 기본적으로 사용 설정(true)됩니다.

Unreal Engine 버전 번들 AGP 기본 출시 버전 디버그 기본값 동작
UE 4.21 이하 기존 Gradle 또는 Ant 사용 중지됨 (false) 사용 중지됨 (false) 엔진에서 삽입한 minifyEnabled 구성이 없습니다.
UE 4.22~4.24 3.4 이전 사용 설정됨 (ProGuard) 사용 중지됨 (false) minifyEnabled true가 출시 빌드에서 기본적으로 사용 설정됩니다 (ProGuard 실행).
UE 4.25~5.3 4.0.0 사용 설정됨 (R8) 사용 중지됨 (false) AGP 4.0을 채택하면 출시 빌드에서 R8이 기본적으로 실행됩니다.
UE 5.4~5.7 7.4.2 사용 설정됨 (R8) 사용 중지됨 (false) AGP 7.x에서는 기존 useProguard 옵션이 삭제되고 R8이 단독으로 실행됩니다.
UE 5.8 (5.8.3+) 8.13.0 사용 설정됨 (R8) 사용 중지됨 (false) 기본적으로 AGP 8.x 및 최신 R8 최적화 파이프라인을 사용합니다.

출시 및 디버그 빌드 차이점

UnrealBuildTool (UEDeployAndroid.cs)은 생성된 buildAdditions.gradle 파일을 출시 빌드와 디버그 빌드에 따라 다르게 구성합니다.

buildTypes {
    release {
        signingConfig signingConfigs.release
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        debuggable true
        signingConfig signingConfigs.debug
    }
}
  • 출시 (배송 또는 배포): minifyEnabled true를 설정하고 기본적으로 proguard-rules.pro를 적용하여 R8 코드 축소 및 난독화를 실행합니다.
  • 디버그 (개발): debuggable true를 사용 설정하고 minifyEnabled를 생략하여(기본값은 false) 빠른 빌드 반복 및 기호 디버깅을 유지합니다.

Unreal 플러그인 언어 (UPL)를 사용하여 유지 규칙 추가

R8은 UE 4.25 이상의 출시 빌드에서 자동으로 실행되므로 C++ JNI (JNIEnv->FindClass, GetMethodID) 또는 매니페스트를 통해서만 도달하는 Java 클래스를 보존해야 합니다. Java 호출 사이트가 없는 클래스는 사용되지 않는 것으로 간주되고 R8에 의해 삭제됩니다. 이로 인해 개발 빌드에서 작동하는 기능이 배송 빌드에서 ClassNotFoundException 또는 NoSuchMethodError로 인해 실패할 수 있습니다.

Unreal 플러그인 언어(UPL) XML 파일에서 <proguardAdditions> 태그를 사용하여 패키징 중에 맞춤 유지 규칙을 proguard-rules.pro에 병합합니다. 프로젝트 또는 플러그인 *_UPL.xml 파일에 다음 블록을 추가합니다.

<root xmlns:android="http://schemas.android.com/apk/res/android">
    <proguardAdditions>
        <insert>
            -keep class com.epicgames.unreal.** { *; }
            -keep class com.example.plugin.** { public *; }
            -dontwarn com.example.plugin.**
        </insert>
    </proguardAdditions>
</root>

일반적인 문제 해결

이 섹션에서는 Unreal Engine에서 R8을 사용할 때 발생하는 일반적인 패키징 및 런타임 문제를 해결하는 방법을 설명합니다.

디버깅을 위해 일시적으로 R8 사용 중지

출시 전용 비정상 종료가 R8에서 필수 클래스를 제거하여 발생하는지 확인하려면 UPL 파일의 <gradleProperties> 아래에 DISABLE_MINIFY=1를 삽입합니다. UEDeployAndroid.cs가 있으면 minifyEnabled false가 생성됩니다.

<gradleProperties>
    <insert>
        DISABLE_MINIFY=1
    </insert>
</gradleProperties>

패키징 오류 Missing classes detected while running R8개

UE 5.4 이상 (AGP 7.4.2 이상)에서는 R8이 엄격한 누락 클래스 검사를 시행합니다. 이 오류로 인해 패키징이 실패하면 중간 빌드 디렉터리 (Intermediate/Android/.../gradle/app/build/outputs/mapping/release/missing_rules.txt 아래)에서 missing_rules.txt를 검사하고 누락된 라이브러리 종속 항목 또는 필수 규칙을 UPL 파일의 <proguardAdditions>에 추가합니다.

서드 파티 SDK와의 R8 전체 모드 호환성

UE 5.8 이상 (AGP 8.13.0 이상)에서는 더 적극적인 최적화를 실행하기 위해 R8 전체 모드가 기본적으로 사용 설정됩니다. 리플렉션 문제로 인해 기존 서드 파티 Android SDK가 런타임에 실패하는 경우 플러그인의 ProGuard 규칙을 업데이트하거나 UPL 파일에 다음 속성을 추가하여 R8을 호환성 모드로 되돌립니다.

<gradleProperties>
    <insert>
        android.enableR8.fullMode=false
    </insert>
</gradleProperties>