キープルールを使用する際は、アプリの動作を維持しながらメリットを享受できるよう、適切なレベルの具体性を確保することが重要です。保持ルールの適切なパターンと避けるべき事項については、以降のセクションをご覧ください。
保持ルールの適切なパターン
明確に定義された保持ルールは、できるだけ具体的です。
クラス仕様では、次の例に示すように、可能な限り常に特定のクラス、ベースクラス、またはアノテーション付きクラスを指定します。
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }
-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }
-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }
可能な場合は、ソースコードにアノテーション(
@Keep
アノテーションなど)を使用し、keep ルールでそれらのアノテーションを直接ターゲットにします。これにより、コードとそれを保持するルール間の明確で明示的なリンクが作成され、構成がより堅牢になり、理解しやすくなり、コードの変更時に破損しにくくなります。たとえば、
androidx.annotation
などのライブラリは、このパターンを使用します。// In your source code @Keep class MyDataClass { /* ... */ } // In your R8 rules -keep @androidx.annotation.DisplayComponent class * {*;}
コード部分が保持される理由について意味のあるコンテキストを提供するように、アノテーションに名前を付けることをおすすめします。たとえば、表示コンポーネントで一部を保持する必要があるアプリには
@DisplayComponent
を使用します。可能であれば、メンバー仕様を宣言し、アプリの機能維持に必要なクラスの部分のみを参照する必要があります。厳密に必要でない限り、オプションのメンバー スコープを
{ *; }
として定義して、ルールをクラス全体に適用しないことをおすすめします。-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }
repackageclasses
グローバル オプションを使用する場合は、省略可能なパッケージ名を指定しないでください。パッケージ接頭辞が再パッケージ化されたクラス名で省略されるため、DEX ファイルのサイズが小さくなります。
これらのガイドラインに準拠できない場合は、保持する必要があるコードを専用のパッケージに一時的に分離し、そのパッケージに保持ルールを適用できます。ただし、これは長期的な解決策ではありません。詳細については、最適化を段階的に導入するをご覧ください。パッケージに保持ルールを使用するには、次の例に示すように保持ルールを定義します。
-keepclassmembers class com.example.pkg.** { *; }
非推奨事項
保持ルールの構文には多くのオプションがありますが、測定可能な持続可能なパフォーマンス上のメリットを得るには、次のオプションを使用しないことをおすすめします。
- 反転演算子
!
を保持ルールで使用しないでください。アプリケーション内のほぼすべてのクラスにルールが誤って適用される可能性があります。 -keep class com.example.pkg.** { *; }
long-term などのパッケージ全体の保持ルールは使用しないでください。R8 を構成する際に問題が発生した場合、一時的に使用して問題を回避できます。詳細については、最適化の範囲を制限するをご覧ください。通常、ワイルドカードには注意が必要です。必要なコードのみを保持していることを確認してください。
これらのルールに従えない場合は、オープン エンドのリフレクションを多用している可能性があるため、リフレクションを避けるか、リフレクションを使用するライブラリを避ける必要があります(Gson のケーススタディを参照)。