使用 R8 缩减和优化虚幻引擎代码

虽然 Unreal Engine 中的核心游戏逻辑是用 C++ 或蓝图编写的,但 Android 打包会编译 Java 和 Kotlin 字节码 (classes.dex),以处理 GameActivity 生命周期事件、Google Play 服务、结算、音频和分析插件。

R8 是 Android Gradle 插件 (AGP) 中的默认代码缩减器和优化器,可移除未使用的类和方法,并优化字节码。这不仅可以缩减软件包下载大小,还可以减少内存映射 (mmap) DEX 页面和基准 Java 进程开销的运行时内存占用,从而缓解物理内存压力和低内存终止守护程序 (LMK) 终止。Google Play 还会通过 Android Vitals 中的 DEX 代码优化指标监控游戏的 DEX 优化级别。

默认行为和 Unreal Engine 版本支持

从 UE 4.22.0 开始,虚幻引擎的 UEDeployAndroid.cs 默认会将 minifyEnabled true 注入生成的 Android 发布 build 配置 (buildAdditions.gradle) 中。由于 UE 4.25 将捆绑的工具链升级到了 AGP 4.0.0,因此在 UE 4.25 及更高版本中,所有发布(交付和分发)build 默认启用 R8 (true),无需额外设置。

Unreal Engine 版本 捆绑式 AGP 默认版本 默认调试 行为
UE 4.21 及更低版本 旧版 Gradle 或 Ant 已停用 (false) 已停用 (false) 引擎未注入 minifyEnabled 配置。
UE 4.22 至 4.24 早于 3.4 已启用 (ProGuard) 已停用 (false) minifyEnabled true 在发布 build 中默认启用(运行 ProGuard)。
UE 4.25 至 5.3 4.0.0 已启用 (R8) 已停用 (false) AGP 4.0 采用在发布 build 中默认运行 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 优化流水线。

Release build 与 调试 build 的差异

UnrealBuildTool (UEDeployAndroid.cs) 会针对发布 build 和调试 build 以不同的方式配置生成的 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),以保留快速 build 迭代和符号调试。

使用 Unreal 插件语言 (UPL) 添加 keep 规则

由于 R8 会在 UE 4.25 及更高版本的发布 build 上自动运行,因此您必须保留仅通过 C++ JNI(JNIEnv->FindClass、GetMethodID)或清单访问的 Java 类。没有 Java 调用网站的类会被视为未使用,并被 R8 剥离,这可能会导致在开发 build 中正常运行的功能在发布 build 中因 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 会强制执行严格的类缺失检查。如果打包失败并显示此错误,请检查中间 build 目录(位于 Intermediate/Android/.../gradle/app/build/outputs/mapping/release/missing_rules.txt 下)中的 missing_rules.txt,并将缺少的库依赖项或必需规则添加到 UPL 文件中的 <proguardAdditions>。

R8 完整模式与第三方 SDK 的兼容性

在 UE 5.8 及更高版本 (AGP 8.13.0+) 中,R8 完整模式默认处于启用状态,以执行更积极的优化。如果旧版第三方 Android SDK 在运行时因反射问题而失败,请更新插件的 ProGuard 规则,或通过向 UPL 文件添加以下属性,将 R8 还原为兼容模式:

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