デフォルトでは、R8 はパフォーマンスとサイズを改善するために多くの最適化を行いますが、最適化がアプリにすぐに適用されないことがあります。大規模なアプリで初めて R8 を有効にする(またはフルモードを有効にする)場合は、アプリのすべてのコードではなく、コードの一部に対して難読化を一時的に無効にして R8 を有効にするなど、最適化を段階的に導入してください。この段階的なアプローチはローカル開発時に行うことをおすすめしますが、 内部 QA テストや、段階的なロールアウトとして本番環境でも使用できます。 具体的な手順は、目標とするタイムラインと、リリース前のテスト範囲に対する信頼度によって異なります。
最適化を制限する
R8 は、コードの削除、コードの書き換え、リソースの削除など、さまざまな種類の最適化を行います。最適化の種類について、概要を以下に示します。
- コード圧縮(ツリー シェイキング): 参照されていないコードを削除します
- 難読化(識別子の最小化): クラスとメソッドの名前を短縮します
- 最適化: コードを書き換えます(インライン化など)
エラーが発生する可能性を減らすため、まずはこれらの最適化の一部のみを有効にすることをおすすめします。
ツリー シェイキングのみを有効にする
コード圧縮(ツリー シェイキングとも呼ばれます)は、参照されていないと思われるコードを削除します。最も簡単なツリー シェイキングから始めることをおすすめします。
ツリー シェイキングのみを有効にするには、proguard-rules.pro ファイルに次の行を追加して、他の種類の最適化を無効にします。難読化を無効にすると、スタック トレースが読みやすくなるため、非常に重要です。
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
最終的に、この構成でリリースすることはおすすめしません。R8 によるコードの最適化が大幅に制限されるためです。ただし、修正すべき問題がある大規模なコードベースで初めて R8 を導入する場合は、優れた出発点となります。
互換モードを使用する
デフォルトでは、R8 は フルモードで実行されます。フルモードでは、パフォーマンスとサイズの削減が大幅に向上しますが、最小化を初めて有効にする場合は、一時的に無効にして互換モードを使用できます。
互換モードを使用するには、gradle.properties ファイルで次の設定を使用します。
android.enableR8.fullMode = false // Use temporarily to disable full mode
残りの最適化を有効にする
ツリー シェイキングがアプリで機能することを確認したら、上記の設定を削除して、難読化、最適化、R8 フルモードを再度有効にできます。 難読化を行うとデバッグが難しくなる可能性があるため、まずはツリー シェイキングの問題に対処することをおすすめします。
スタック トレースの難読化解除について詳しくは、 元のスタック トレースを復元するをご覧ください。
最適化の範囲を制限する
完全に最適化されたビルドでは、すべてのライブラリとパッケージのすべてのコードが最適化されるため、R8 を初めて有効にすると問題が発生することがよくあります。アプリの一部で最適化に問題が見つかった場合は、R8 を完全に無効にしないでください。他の部分のメリットが失われます。代わりに、問題を引き起こしているアプリの部分でのみ、R8 を一時的に無効にします。
パッケージ全体の keep ルールを使用する
アプリの一部で R8 を一時的に無効にする方法として、パッケージ全体の keep ルールを使用することをおすすめします。後で必ずこれらの最適化の問題を修正する必要があります。これは通常、問題のある領域を回避するための一時的な解決策です。
たとえば、アプリの一部で Gson が多用されており、
最適化に問題が発生している場合、理想的な解決策は、より
ターゲットを絞った keep ルールを追加するか、codegen ソリューションに移行することです。ただし、アプリの残りの部分の最適化をブロック解除するには、Gson 型を定義するコードを専用のサブパッケージに配置し、proguard-rules.pro ファイルに次のようなルールを追加します。
-keep class com.myapp.json.** { *; }
使用しているライブラリの一部に内部コンポーネントへの リフレクションがある場合は、同様にライブラリ全体に対して keep ルールを追加できます。keep する適切なパッケージを見つけるには、ライブラリのコードまたは JAR/AAR を調べる必要があります。繰り返しになりますが、長期的に維持することはおすすめしませんが、アプリの残りの部分の最適化をブロック解除できます。
-keep class com.somelibrary.** { *; }
パッケージ全体の keep ルールを削除する
パッケージ全体の keep ルールでアプリが正しく機能するようになったら、 ターゲットを絞ったkeep ルールを追加するか、 keep ルールが必要となるリフレクションの使用またはライブラリを削除します。
たとえば、関連するクラスのみを保持するために、特定のクラスを拡張するすべてのルールを保持することは、AndroidX では非常に一般的です。通常、リフレクションは、特定の抽象クラスを拡張するクラスまたはメソッド、特定のインターフェースを実装するクラスまたはメソッド、特定のランタイム アノテーションを持つクラスのみを対象とする必要があります。これらはすべて、最終的に完全に最適化されたアプリでパッケージ全体の keep ルールが不要になるように、keep ルールを定義するサポートされている方法です。
独自コードベースにリフレクションが存在する場合は、パッケージ全体の keep ルールを Jetpack Keep に置き換えることができます。生成されたルールは条件付きです。R8 は、リフレクション呼び出しのターゲットを、呼び出しを行うコードも保持する場合にのみ保持します。パッケージを移行するには、Jetpack Keep lint チェックを使用して リフレクション呼び出しを見つけてアノテーションを付け、パッケージ全体のルールを削除します。