Shrink and optimize Unreal Engine code with R8

Although your core game logic in Unreal Engine is written in C++ or Blueprints, Android packaging compiles Java and Kotlin bytecode (classes.dex) to handle GameActivity lifecycle events, Google Play services, billing, audio, and analytics plugins.

R8, the default code shrinker and optimizer in the Android Gradle Plugin (AGP), removes unused classes and methods and optimizes bytecode. This not only decreases your package download size, but also reduces the runtime memory footprint of memory-mapped (mmap) DEX pages and baseline Java process overhead, mitigating physical memory pressure and low memory killer (LMK) terminations. Google Play also monitors your game's DEX optimization levels through the DEX code optimization metric in Android vitals.

Default behavior and Unreal Engine version support

Starting in UE 4.22.0, Unreal Engine's UEDeployAndroid.cs injects minifyEnabled true into the generated Android Release build configuration (buildAdditions.gradle) by default. Because UE 4.25 upgraded the bundled toolchain to AGP 4.0.0, R8 is enabled by default (true) on all Release (Shipping and Distribution) builds in UE 4.25 and higher without additional setup.

Unreal Engine version Bundled AGP Release default Debug default Behavior
UE 4.21 and earlier Legacy Gradle or Ant Disabled (false) Disabled (false) No minifyEnabled configuration injected by the engine.
UE 4.22 to 4.24 Earlier than 3.4 Enabled (ProGuard) Disabled (false) minifyEnabled true enabled by default in Release builds (runs ProGuard).
UE 4.25 to 5.3 4.0.0 Enabled (R8) Disabled (false) AGP 4.0 adoption runs R8 by default in Release builds.
UE 5.4 to 5.7 7.4.2 Enabled (R8) Disabled (false) AGP 7.x removes legacy useProguard options; R8 runs exclusively.
UE 5.8 (5.8.3+) 8.13.0 Enabled (R8) Disabled (false) Uses AGP 8.x and modern R8 optimization pipelines by default.

Release and Debug build differences

UnrealBuildTool (UEDeployAndroid.cs) configures the generated buildAdditions.gradle file differently for Release and Debug builds:

buildTypes {
    release {
        signingConfig signingConfigs.release
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        debuggable true
        signingConfig signingConfigs.debug
    }
}
  • Release (Shipping or Distribution): Sets minifyEnabled true and applies proguard-rules.pro by default, running R8 code shrinking and obfuscation.
  • Debug (Development): Enables debuggable true and omits minifyEnabled (defaulting to false) to preserve fast build iteration and symbol debugging.

Add keep rules using Unreal Plugin Language (UPL)

Because R8 runs automatically on Release builds in UE 4.25 and higher, you must preserve Java classes reached only through C++ JNI (JNIEnv->FindClass, GetMethodID) or the manifest. Classes without Java call sites are treated as unused and stripped by R8, which can cause features that work in Development builds to fail with ClassNotFoundException or NoSuchMethodError in Shipping builds.

Use the <proguardAdditions> tag in an Unreal Plugin Language (UPL) XML file to merge custom keep rules into proguard-rules.pro during packaging. Add the following block to your project or plugin *_UPL.xml file:

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

Troubleshoot common issues

This section describes how to resolve common packaging and runtime issues when using R8 in Unreal Engine.

Temporarily disable R8 for debugging

To isolate whether a Release-only crash is caused by R8 stripping required classes, insert DISABLE_MINIFY=1 under <gradleProperties> in your UPL file. When present, UEDeployAndroid.cs generates minifyEnabled false:

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

Missing classes detected while running R8 packaging errors

In UE 5.4 and higher (AGP 7.4.2+), R8 enforces strict missing-class checks. If packaging fails with this error, inspect missing_rules.txt in your intermediate build directory (under Intermediate/Android/.../gradle/app/build/outputs/mapping/release/missing_rules.txt) and add the missing library dependencies or required rules to <proguardAdditions> in your UPL file.

R8 full mode compatibility with third-party SDKs

In UE 5.8 and higher (AGP 8.13.0+), R8 full mode is enabled by default to perform more aggressive optimizations. If a legacy third-party Android SDK fails at runtime due to reflection issues, update the plugin's ProGuard rules or revert R8 to compatibility mode by adding the following property to your UPL file:

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