Cuando trabajes con reglas de conservación, es importante alcanzar el nivel adecuado de especificidad para asegurarte de ver los beneficios y, al mismo tiempo, mantener el comportamiento de tu app. Consulta las siguientes secciones para obtener información sobre los buenos patrones y las cosas que debes evitar en las reglas de conservación.
Buenos patrones en las reglas de conservación
Las reglas de conservación bien definidas son lo más específicas posible:
Para la especificación de la clase, siempre especifica una clase, una clase base o una clase anotada específicas, si es posible, como se muestra en los siguientes ejemplos:
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }
-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }
-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }
Siempre que sea posible, usa anotaciones en tu código fuente (como una anotación
@Keep
) y, luego, segmenta esas anotaciones directamente en tus reglas de conservación. Esto crea un vínculo claro y explícito entre tu código y las reglas que lo conservan, lo que hace que tu configuración sea más sólida, fácil de comprender y menos propensa a fallas cuando cambia el código.Por ejemplo, las bibliotecas como
androidx.annotation
usan este patrón:// In your source code @Keep class MyDataClass { /* ... */ } // In your R8 rules -keep @androidx.annotation.DisplayComponent class * {*;}
Te recomendamos que nombres tus anotaciones de manera que proporcionen un contexto significativo sobre por qué se conservan partes del código. Por ejemplo, usa
@DisplayComponent
para una app en la que los componentes de visualización requieren que se conserven algunas partes.Siempre que sea posible, se debe declarar la especificación del miembro y solo hacer referencia a las partes de la clase que se deben conservar para que la app funcione. Se recomienda no aplicar una regla a toda una clase definiendo el alcance del miembro opcional como
{ *; }
, a menos que sea estrictamente necesario.-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }
Si usas la opción global
repackageclasses
, evita especificar el nombre del paquete opcional. Esto genera archivos DEX más pequeños, ya que el prefijo del paquete se omite en los nombres de las clases reempaquetadas.
Si no puedes cumplir con estos lineamientos, puedes aislar temporalmente el código que debe conservarse en un paquete dedicado y aplicar tu regla de conservación al paquete. Sin embargo, esta no es una solución a largo plazo. Para obtener más información, consulta Adopta optimizaciones de forma incremental. Para usar una regla de conservación para un paquete, define una regla de conservación como se muestra en el siguiente ejemplo:
-keepclassmembers class com.example.pkg.** { *; }
Elementos que debes evitar
La sintaxis de las reglas de conservación tiene muchas opciones, pero, para obtener beneficios de rendimiento sostenibles y medibles, te recomendamos que no uses las siguientes:
- Evita usar el operador de inversión
!
en las reglas de conservación, ya que podrías aplicar una regla de forma no intencional a casi todas las clases de tu aplicación. - No uses reglas de conservación para todo el paquete, como
-keep class com.example.pkg.** { *; }
, a largo plazo. Se pueden usar de forma temporal para solucionar problemas cuando se configura R8. Para obtener más información, consulta Cómo limitar el alcance de la optimización. En general, ten cuidado con los comodines y asegúrate de conservar solo el código que necesitas.
Si no puedes seguir estas reglas, es posible que estés usando mucha reflexión de extremo abierto, por lo que deberías evitar la reflexión o la biblioteca que usa la reflexión (consulta el caso de estudio de Gson).