Best Practices befolgen

Bei der Arbeit mit Aufbewahrungsregeln ist es wichtig, den richtigen Grad an Spezifität zu erreichen, damit Sie Vorteile sehen und gleichzeitig das Verhalten Ihrer App beibehalten. In den folgenden Abschnitten finden Sie Informationen zu guten Mustern und dazu, was Sie in Aufbewahrungsregeln vermeiden sollten.

Gute Muster in Aufbewahrungsregeln

Gut definierte Aufbewahrungsregeln sind so spezifisch wie möglich:

  • Geben Sie für die Klassenspezifikation nach Möglichkeit immer eine bestimmte Klasse, Basisklasse oder annotierte Klasse an, wie in den folgenden Beispielen gezeigt:

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • Verwenden Sie nach Möglichkeit Anmerkungen in Ihrem Quellcode (z. B. eine @Keep-Anmerkung) und richten Sie Ihre Keep-Regeln dann direkt auf diese Anmerkungen aus. So wird eine klare, explizite Verbindung zwischen Ihrem Code und den Regeln hergestellt, die ihn schützen. Das macht Ihre Konfiguration robuster, leichter verständlich und weniger anfällig für Fehler bei Codeänderungen.

    Beispielsweise verwenden Bibliotheken wie androidx.annotation dieses Muster:

    // In your source code
    @Keep
    class MyDataClass { /* ... */ }
    
    // In your R8 rules
    -keep @androidx.annotation.DisplayComponent class * {*;}
    

    Wir empfehlen, Ihre Anmerkungen so zu benennen, dass sie einen aussagekräftigen Kontext dafür liefern, warum Codeabschnitte beibehalten werden. Verwenden Sie beispielsweise @DisplayComponent für eine App, bei der für die Anzeige von Komponenten einige Teile beibehalten werden müssen.

  • Die Mitgliedsspezifikation sollte nach Möglichkeit deklariert werden und nur auf die Teile der Klasse verweisen, die für die Funktion der App beibehalten werden müssen. Es wird empfohlen, eine Regel nicht auf eine ganze Klasse anzuwenden, indem Sie den optionalen Mitgliedsbereich als { *; } definieren, es sei denn, dies ist unbedingt erforderlich.

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • Wenn Sie die globale Option repackageclasses verwenden, sollten Sie den optionalen Paketnamen nicht angeben. Dadurch werden die DEX-Dateien kleiner, da das Paketpräfix in den neu verpackten Klassennamen weggelassen wird.

Wenn Sie diese Richtlinien nicht einhalten können, können Sie den Code, der beibehalten werden muss, vorübergehend in einem dedizierten Paket isolieren und Ihre Keep-Regel auf das Paket anwenden. Dies ist jedoch keine langfristige Lösung. Weitere Informationen finden Sie unter Optimierungen schrittweise einführen. Wenn Sie eine Keep-Regel für ein Paket verwenden möchten, definieren Sie eine Keep-Regel wie im folgenden Beispiel:

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

Was du vermeiden solltest

Die Syntax für Aufbewahrungsregeln bietet viele Optionen. Für messbare nachhaltige Leistungssteigerungen empfehlen wir jedoch, Folgendes nicht zu verwenden:

  • Vermeiden Sie die Verwendung des Inversionsoperators ! in Keep-Regeln, da Sie eine Regel sonst möglicherweise versehentlich auf fast jede Klasse in Ihrer Anwendung anwenden.
  • Verwenden Sie keine paketweiten Keep-Regeln wie -keep class com.example.pkg.** { *; } langfristig. Sie können vorübergehend verwendet werden, um Probleme bei der Konfiguration von R8 zu umgehen. Weitere Informationen finden Sie unter Optimierungsbereich einschränken. Seien Sie generell vorsichtig mit Platzhaltern und achten Sie darauf, dass Sie nur den Code beibehalten, den Sie benötigen.

Wenn Sie diese Regeln nicht einhalten können, verwenden Sie möglicherweise viel offene Reflexion. In diesem Fall sollten Sie die Reflexion oder die Bibliothek, die Reflexion verwendet, vermeiden (siehe die Gson-Fallstudie).