Zmniejszanie i optymalizowanie kodu Unreal Engine za pomocą R8

Chociaż podstawowa logika gry w Unreal Engine jest napisana w języku C++ lub Blueprints, pakowanie na Androida kompiluje kod bajtowy Javy i Kotlina (classes.dex) do obsługi zdarzeń cyklu życia GameActivity, Usług Google Play, płatności, dźwięku i wtyczek analitycznych.

R8, domyślne narzędzie do zmniejszania i optymalizacji kodu we wtyczce Androida do obsługi Gradle (AGP), usuwa nieużywane klasy i metody oraz optymalizuje kod bajtowy. Zmniejsza to nie tylko rozmiar pobieranego pakietu, ale też wykorzystanie pamięci przez strony DEX mapowane w pamięci (mmap) i narzut podstawowego procesu Javy, co zmniejsza obciążenie pamięci fizycznej i ogranicza liczbę zakończeń przez LMK (Low Memory Killer). Google Play monitoruje też poziomy optymalizacji plików DEX w grze za pomocą danych Optymalizacja kodu DEX w Android Vitals.

Działanie domyślne i obsługa wersji Unreal Engine

Od wersji UE 4.22.0 UEDeployAndroid.cs Unreal Engine domyślnie wstrzykuje minifyEnabled true do wygenerowanej konfiguracji kompilacji do publikacji na Androida (buildAdditions.gradle). Ponieważ w UE 4.25 dołączony łańcuch narzędzi został uaktualniony do AGP 4.0.0, R8 jest domyślnie włączony (true) we wszystkich kompilacjach wersji (wysyłkowych i dystrybucyjnych) w UE 4.25 i nowszych bez dodatkowej konfiguracji.

Wersja Unreal Engine Połączone AGP Zwolnij domyślne Domyślne debugowanie Zachowanie
UE 4.21 i starsze Starsza wersja Gradle lub Ant Wyłączone (false) Wyłączone (false) Silnik nie wstrzyknął konfiguracji minifyEnabled.
UE 4.22–4.24 Wcześniej niż 3.4 Włączone (ProGuard) Wyłączone (false) Funkcja minifyEnabled true jest domyślnie włączona w kompilacjach do publikacji (uruchamia ProGuard).
UE 4.25–5.3 4.0.0 Włączono (R8) Wyłączone (false) Wtyczka Androida do obsługi Gradle 4.0 domyślnie uruchamia R8 w kompilacjach do publikacji.
UE 5.4–5.7 7.4.2 Włączono (R8) Wyłączone (false) Wtyczka Androida do obsługi Gradle 7.x usuwa starsze opcje useProguard. Działa tylko R8.
UE 5.8 (5.8.3+) 8.13.0 Włączono (R8) Wyłączone (false) Domyślnie używa AGP 8.x i nowoczesnych potoków optymalizacji R8.

Różnice między kompilacjami do wydania i do debugowania

UnrealBuildTool (UEDeployAndroid.cs) konfiguruje wygenerowany plik buildAdditions.gradle inaczej w przypadku kompilacji wersji i kompilacji do debugowania:

buildTypes {
    release {
        signingConfig signingConfigs.release
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        debuggable true
        signingConfig signingConfigs.debug
    }
}
  • Wersja (wysyłka lub dystrybucja): ustawia minifyEnabled true i domyślnie stosuje proguard-rules.pro, uruchamiając zmniejszanie kodu R8 i zaciemnianie kodu.
  • Debug (Development): włącza debuggable true i pomija minifyEnabled (domyślnie false), aby zachować szybką iterację kompilacji i debugowanie symboli.

Dodawanie reguł zachowywania za pomocą języka Unreal Plugin Language (UPL)

R8 działa automatycznie w kompilacjach do publikacji w UE 4.25 i nowszych, dlatego musisz zachować klasy Javy, do których można dotrzeć tylko przez JNI C++ (JNIEnv->FindClass, GetMethodID) lub plik manifestu. Klasy bez witryn wywołań Java są traktowane jako nieużywane i usuwane przez R8, co może powodować, że funkcje, które działają w kompilacjach deweloperskich, nie działają w kompilacjach produkcyjnych i powodują błąd ClassNotFoundException lub NoSuchMethodError.

Użyj tagu <proguardAdditions> w pliku XML Unreal Plugin Language (UPL), aby podczas pakowania scalić niestandardowe reguły zachowywania z plikiem proguard-rules.pro. Dodaj do pliku *_UPL.xml projektu lub wtyczki ten blok:

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

Rozwiązywanie typowych problemów

W tej sekcji opisano, jak rozwiązywać typowe problemy z pakowaniem i środowiskiem wykonawczym podczas korzystania z R8 w Unreal Engine.

Tymczasowe wyłączanie R8 na potrzeby debugowania

Aby sprawdzić, czy awaria występująca tylko w wersji produkcyjnej jest spowodowana usunięciem przez R8 wymaganych klas, wstaw DISABLE_MINIFY=1 pod <gradleProperties> w pliku UPL. Gdy jest obecny, UEDeployAndroid.cs generuje minifyEnabled false:

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

Missing classes detected while running R8 błąd pakowania

W UE 5.4 i nowszych (AGP 7.4.2+) R8 rygorystycznie sprawdza brakujące klasy. Jeśli pakowanie nie powiedzie się z powodu tego błędu, sprawdź plik missing_rules.txt w pośrednim katalogu kompilacji (w Intermediate/Android/.../gradle/app/build/outputs/mapping/release/missing_rules.txt) i dodaj brakujące zależności biblioteki lub wymagane reguły do <proguardAdditions> w pliku UPL.

Zgodność trybu pełnego R8 z pakietami SDK innych firm

W UE w wersji 5.8 lub nowszej (AGP 8.13.0+) tryb pełny R8 jest domyślnie włączony, aby przeprowadzać bardziej agresywne optymalizacje. Jeśli starszy pakiet Android SDK innej firmy nie działa w czasie działania z powodu problemów z refleksją, zaktualizuj reguły ProGuard wtyczki lub przywróć tryb zgodności R8, dodając do pliku UPL tę właściwość:

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