ベスト プラクティスに従う

keep ルールを使用する場合は、アプリの動作を維持しながらメリットを得られるように、適切なレベルの具体性を確保することが重要です。keep ルールの適切なパターンと避けるべき事項については、次のセクションをご覧ください。

keep ルールの適切なパターン

適切に定義された keep ルールは、可能な限り具体的であり、次のパターンに準拠しています。

  • クラスの指定では、可能な限り、次の例に示すように、特定のクラス、基本クラス、またはアノテーション付きクラスを常に指定します。

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • 可能な限り、ソースコードにアノテーションを使用し、keep ルールでそれらのアノテーションを直接ターゲットにします。これにより、コードとそれを保持するルールとの間に明確で明示的なリンクが作成され、構成がより堅牢になり、理解しやすくなり、コードの変更時に破損しにくくなります。

    たとえば、次のスニペットは、クラス MyClass と、@com.example.DisplayComponent アノテーションが付いた他のクラスを保持する方法を示しています。

    // In the source code
    @com.example.DisplayComponent
    class MyClass { /* ... */ }
    
    // In the keep rules
    -keep @com.example.DisplayComponent class * {*;}
    

    コードの一部が保持される理由について意味のあるコンテキストを提供するように、アノテーションに名前を付けることをおすすめします。たとえば、表示コンポーネントで一部を保持する必要があるアプリには、@DisplayComponent を使用します。

  • 可能な限り、メンバーの指定を宣言し、アプリが機能するために保持する必要があるクラスの部分のみを参照します。 厳密に必要な場合を除き、オプションのメンバー スコープを { *; } として定義して、ルールをクラス全体に適用しないことをおすすめします。

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • repackageclasses グローバル オプションを使用する場合は、 オプションのパッケージ名を指定しないでください。パッケージの接頭辞がリパッケージされたクラス名で省略されるため、DEX ファイルが小さくなります。

  • リフレクションによってアクセスされるすべてのアイテムの keep ルールを維持します。明示的な keep ルールがなくても、このようなアイテムは R8 によって保持されますが、今後のコード変更によって R8 がこれらのアイテムを保持しなくなる可能性があるため、実際のルールを維持することが重要です。

    独自のコードのリフレクションでは、Jetpack Keep を 使用して、保守が容易な keep ルールを生成できます。各アノテーションはリフレクションを実行するコードに付いているため、そのコードを変更すると、同じ場所でアノテーションを更新または削除できます。これにより、アプリがリフレクションしなくなったコードがルールによって保持されることはありません。Lint は、アノテーションが付いていないリフレクション呼び出しにもフラグを設定します。

  • 可能な場合は、-assumenosideeffects または -convertchecknotnull を使用して null チェックを最適化します。これにより、アプリの DEX のサイズを大幅に削減できます。詳細については、追加のルールタイプをご覧ください。

これらのガイドラインに準拠できない場合は、保持する必要があるコードを専用のパッケージに一時的に分離し、そのパッケージに keep ルールを適用できます。ただし、これは長期的な解決策ではありません。詳細については、 最適化を段階的に導入するをご覧ください。パッケージに keep ルールを使用するには、次の例に示すように keep ルールを定義します。

-keepclassmembers class com.example.pkg.** { *; }

非推奨事項

keep ルールの構文には多くのオプションがありますが、持続可能なパフォーマンスのメリットを測定するには、次のものを使用しないことをおすすめします。

  • -keep class com.example.pkg.** { *; } などのパッケージ全体の keep ルールは、長期的に使用しないでください。R8 の構成時に問題が発生した場合に、一時的に使用できます。詳細については、最適化の範囲を制限するをご覧ください。 一般に、ワイルドカードを使用する場合は注意が必要です。必要なコードのみを保持していることを確認してください。
  • 可能な限り、ライブラリを使用する際に keep ルール(特にパッケージ全体の keep ルール)をコピーして貼り付けるように求めるライブラリは避けてください。Android で適切に動作するように設計されたライブラリは、可能な限りリフレクションを避け、 必要に応じて コンシューマーの keep ルールを埋め込む必要があります。
  • keep ルールで反転演算子 ! を使用しないでください。誤ってアプリのほぼすべてのクラスにルールを適用してしまう可能性があります。

これらのルールに従えない場合は、オープンエンドの リフレクションを多用している可能性があります。リフレクションを避けるか、リフレクションを使用するライブラリを避ける必要があります(Gson のケーススタディをご覧ください)。