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 最適化レベルもモニタリングします。

デフォルトの動作と Unreal Engine バージョンのサポート

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 Plugin Language(UPL)を使用して保持ルールを追加する

R8 は UE 4.25 以降のリリースビルドで自動的に実行されるため、C++ JNI(JNIEnv->FindClass、GetMethodID)またはマニフェストを介してのみアクセスされる Java クラスを保持する必要があります。Java 呼び出しサイトのないクラスは未使用として扱われ、R8 によって削除されます。これにより、開発ビルドで動作する機能が、リリースビルドで ClassNotFoundException または NoSuchMethodError で失敗する可能性があります。

Unreal Plugin Language(UPL)の XML ファイルで <proguardAdditions> タグを使用して、パッケージ化中にカスタムの keep ルールを 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> に追加します。

R8 フルモードとサードパーティ SDK の互換性

UE 5.8 以降(AGP 8.13.0+)では、より積極的な最適化を行うために、R8 フルモードがデフォルトで有効になっています。リフレクションの問題が原因で、以前のサードパーティ製 Android SDK が実行時に失敗する場合は、プラグインの ProGuard ルールを更新するか、UPL ファイルに次のプロパティを追加して R8 を互換モードに戻します。

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