Adopta optimizaciones de forma incremental

De forma predeterminada, R8 realiza muchas optimizaciones para mejorar el rendimiento y el tamaño, pero es posible que las optimizaciones no funcionen de inmediato para tu app. Si activas R8 (o habilitas el modo completo) en una app grande por primera vez, intenta adoptar las optimizaciones de forma incremental: desactiva temporalmente la ofuscación y habilita R8 para partes del código a la vez, en lugar de todo el código de la app. Te recomendamos que adoptes este enfoque incremental durante el desarrollo local, pero también puedes usarlo durante las pruebas de control de calidad internas o incluso en producción como un lanzamiento gradual. Los pasos exactos que realices dependerán del cronograma deseado y de la confianza en la cobertura de las pruebas previas al lanzamiento.

Limita las optimizaciones

R8 realiza muchos tipos de optimizaciones, como quitar código, volver a escribirlo y quitar recursos. Estas son algunas descripciones generales de los tipos de optimización:

  • Reducción de código (o eliminación de código muerto): Quita el código sin referencia.
  • Ofuscación (o reducción de identificadores): Acorta los nombres de las clases y los métodos.
  • Optimización: Vuelve a escribir el código, por ejemplo, intercalando

Para reducir las posibilidades de errores, puedes comenzar por habilitar solo algunas de estas optimizaciones.

Habilita solo el movimiento de árboles

La reducción de código, también conocida como eliminación de código muerto, quita el código que parece no tener referencias. Te recomendamos que comiences solo con el agitado de árboles, ya que es la opción más directa.

Para habilitar solo el movimiento de árboles, agrega lo siguiente a tu archivo proguard-rules.pro para desactivar los otros tipos de optimizaciones. Desactivar la ofuscación es clave porque hace que los seguimientos de pila sean mucho más fáciles de leer.

-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization

En última instancia, no querrás enviar esta configuración, ya que limita de forma drástica la capacidad de R8 para optimizar el código, pero es un excelente punto de partida cuando se adopta R8 por primera vez en una base de código grande con problemas que se deben corregir.

Usa el modo de compatibilidad

De forma predeterminada, R8 se ejecuta en el modo completo. El modo completo ofrece un rendimiento y un ahorro de tamaño significativamente mejorados, pero puedes inhabilitarlo temporalmente y usar el modo de compatibilidad en su lugar cuando habilites la reducción por primera vez.

Para usar el modo de compatibilidad, usa el siguiente parámetro de configuración en tu archivo gradle.properties:

android.enableR8.fullMode = false // Use temporarily to disable full mode

Habilita el resto de las optimizaciones

Cuando confirmes que el movimiento de árboles funciona para tu app, puedes quitar la configuración anterior para volver a habilitar la ofuscación, la optimización y el modo completo de R8. Ten en cuenta que la ofuscación puede dificultar la depuración, por lo que te recomendamos que primero abordes los problemas de eliminación de árboles.

Para obtener más información sobre cómo desofuscar los seguimientos de pila, consulta Recupera el seguimiento de pila original.

Limita el alcance de la optimización

Una compilación completamente optimizada optimiza todo el código en cada biblioteca y paquete, por lo que es común encontrar problemas con R8 cuando lo activas por primera vez. Si encuentras un problema con la optimización en una parte de la app, no desactives R8 por completo, o perderás los beneficios en todas partes. En su lugar, inhabilita temporalmente R8 solo en las partes de la app que causan problemas.

Usa reglas de conservación para todo el paquete

Te recomendamos que uses reglas de retención para todo el paquete como una forma de inhabilitar temporalmente R8 en algunas partes de tu app. Siempre debes volver a solucionar estos problemas de optimización más adelante. Por lo general, esta es una solución provisional para solucionar problemas en áreas problemáticas.

Por ejemplo, si una parte de tu app usa Gson en exceso y causa problemas con la optimización, la solución ideal es agregar más reglas de retención segmentadas o cambiar a una solución de codegen. Sin embargo, para desbloquear la optimización del resto de la app, puedes colocar el código que define tus tipos de Gson en un subpaquete dedicado y agregar una regla como esta a tu archivo proguard-rules.pro:

-keep class com.myapp.json.** { *; }

Si alguna biblioteca que usas tiene reflexión en componentes internos, puedes agregar de manera similar una regla de retención para toda la biblioteca. Deberás inspeccionar el código de la biblioteca o el archivo JAR/AAR para encontrar el paquete adecuado que debes conservar. Una vez más, no se recomienda mantener esta configuración a largo plazo, pero puede desbloquear la optimización del resto de la app:

-keep class com.somelibrary.** { *; }

Quita las reglas de retención de todo el paquete

Una vez que tu app funcione correctamente con las reglas de conservación de todo el paquete, debes volver y agregar reglas de conservación segmentadas o quitar el uso o la biblioteca de reflexión que requiere la regla de conservación en primer lugar.

Por ejemplo, es muy común en AndroidX mantener todas las reglas que extienden una clase determinada para conservar solo las clases relevantes. En general, la reflexión solo debe orientarse a clases o métodos que extienden ciertas clases abstractas, implementan ciertas interfaces o se orientan a clases con una anotación de tiempo de ejecución específica. Cada una de estas opciones es una forma admitida de definir reglas de retención para que no necesites reglas de retención para todo el paquete en tu app final y completamente optimizada.