
Hola, soy desarrollador de Android y ya no tengo miedo de ProGuard ...
Por lo general, esta utilidad se recuerda cuando se enfrenta con un problema de límite de dex dalvik o con un requisito para mejorar la seguridad de la aplicación. Desafortunadamente, está lejos de ser la primera vez que configura correctamente Proguard. A menudo veía cuántos, después de romper un proyecto, apagaban Proguard y activaban el soporte Mulditex, y cada vez estaba un poco triste por eso, porque Proguard ayuda a reducir el tamaño de la aplicación y a aumentar su rendimiento.
Al final, decidí escribir un artículo en el que puedo poner toda la información útil que aprendí durante varios años de trabajo con Proguard y que podría ayudar tanto a los principiantes como a los que ya saben algo.
De que se trata
Proguard es una utilidad de código abierto para optimizar y ofuscar el código Java. Esta herramienta procesa código Java ya compilado, por lo que debería funcionar con cualquier lenguaje JVM. Más precisamente, el lenguaje en sí para Proguard es indiferente, solo el bytecode es importante. Todas las manipulaciones de bytecode proguard se pueden dividir en 3 categorías principales: reducción de código , optimización y ofuscación .
Reducción de código
Sí, es una tarea bastante extraña escribir código y luego eliminarlo, pero esta es la realidad del desarrollo de Android. Esto, por supuesto, no se trata del código escrito a mano (aunque esto sucede), sino de toneladas de carga muerta traídas por bibliotecas de todo tipo. Guava , Apache Commons , Google Play Services y otros tipos pueden inflar el tamaño del archivo apk de 500 kb a un par de decenas de megabytes. A veces llega tan lejos que un programa no puede compilarse debido a que excede el límite de métodos de Dalvik . Proguard ayudará a eliminar todo el código no utilizado y reducirá el tamaño de la aplicación a unos pocos megabytes.
Optimización
Además de eliminar el código innecesario, Proguard puede optimizar el código restante. Su arsenal incluye análisis de flujo de control, análisis de flujo de datos, evaluación parcial, asignación única estática, numeración de valor global, análisis de vida. Proguard puede realizar optimizaciones de mirilla, reducir el número de asignaciones de variables, simplificar las recursiones de cola y mucho más ( wiki ). Además de tales operaciones generales, Proguard tiene optimizaciones útiles específicamente para la plataforma Android, por ejemplo, reemplazando las clases enum con ints, eliminando las instrucciones de registro.
Ofuscación
Finalmente, Proguard puede convertir todo su código en un desastre ilegible renombrando todas las clases, métodos y campos en conjuntos de letras aleatorias (en realidad no del todo aleatorias). Esta es una opción muy útil, ya que cualquiera puede descompilar su archivo apk, y no todos tienen la paciencia para comprender el código ofuscado.
Principio de funcionamiento
Proguard funciona en 3 pasos en la secuencia descrita anteriormente: reducción de código → optimización → ofuscación . Cada uno de los pasos es opcional.
El paso de optimización en el caso del SDK de Android está desactivado de forma predeterminada.
Para que Proguard funcione, debe proporcionar 3 componentes:
- Su código compilado es un archivo con los archivos de
class
de su programa y todas las bibliotecas que utiliza (jar, aar, apk, war, zip, etc.). Proguard solo modifica el código ya compilado y no tiene nada que ver con la fuente. - Archivo (s) de configuración: archivo (s) que contiene todas las reglas, opciones y configuraciones con las que desea comenzar a procesar.
- Library jars (aar, apks, ...): clases de la plataforma en la que se ejecuta su programa. En el caso de Android, este es
android.jar
. Estos archivos son necesarios solo para el análisis correcto de su código, no se modificarán (esto no tiene sentido, ya que android.jar
está "en el teléfono", no tenemos acceso a él).

(Imagen de la presentación de Jeb Ware, enlace al final del artículo)
Usando clases de biblioteca y sus archivos de configuración, Proguard define todos los puntos de entrada a su programa ( semillas ). En otras palabras, define aquellas clases y métodos que se pueden llamar desde el exterior y que no se pueden tocar. Luego, comenzando con las semillas descubiertas, Proguard atraviesa recursivamente todo su código, marcando "usado" todo lo que pudo alcanzar. Todos los demás códigos serán eliminados. Debe especificar al menos un punto de entrada en la configuración. Para un programa estándar de Java, esta es la función main
. En Android, no hay un único punto de entrada al programa; en cambio, tenemos componentes estándar (Actividad, Servicio, etc.) creados y llamados por el sistema. Afortunadamente, no necesitamos especificar nada aquí por nuestra cuenta, el SDK de Android creará la configuración necesaria para nosotros.
Archivos complementarios
Después de detectar todos los puntos de entrada, Proguard los escribirá en el archivo seeds.txt
.
Todo el código que Proguard consideró innecesario se escribe en el archivo usage.txt
. Este es un nombre bastante extraño para un archivo que contiene código remoto, sería más correcto llamarlo unusage.txt, pero tenemos lo que tenemos, solo recuerda eso.
En el paso de ofuscación, se creará un archivo mapping.txt
que contiene los pares <nombre de clase original | método | campo> -> <nombre de clase ofuscado | método | campo>. Este archivo es útil cuando necesita desofuscar un programa, por ejemplo, leer stacktrace. No es necesario mapear manualmente los archivos; el SDK de Android tiene utilidades de proguardui
y proguardui
para ayudar. Además, si usa Fabric Crashlytics, entonces su complemento gradle puede encontrar y cargar este archivo en la consola de forma independiente, por lo que no necesita preocuparse por ello.
En el caso de Android, estos archivos generalmente se encuentran en app/build/output/mapping/<product-flavor-name>/
.
Proguard también crea un archivo dump.txt
que contiene todo lo que Proguard puso en el archivo final. Nunca fue útil para mí, pero tal vez sea útil para alguien.
¿Cómo van las cosas en Android?
Android Gradle Plugin puede ejecutar Proguard por sí solo. Todo lo que tiene que hacer es habilitar esta opción y especificar los archivos de configuración.
buildTypes { <...> release { minifyEnabled true proguardFiles 'proguard-rules.pro', getDefaultProguardFile('proguard-android.txt') } }
minifyEnabled true
: habilita Proguard en el momento de la compilación
proguardFiles
: una lista de archivos de configuración. Las reglas de todos los archivos de configuración se agregarán a la lista general en el orden en que aparecen.
proguard-rules.pro
es nuestro archivo de configuración con reglas específicas del proyecto
getDefaultProguardFile('proguard-android.txt')
: una función que devuelve el archivo de configuración estándar para aplicaciones de Android. Se encuentra en AndroidSDK/tools/proguard
De hecho, el SDK de Android tiene dos proguard-android.txt
: proguard-android.txt
y proguard-android-optimize.txt
. El primero tiene la opción -dontoptimize
, que desactiva todas las optimizaciones. Si desea habilitar la optimización, use la segunda configuración.
Además de estas configuraciones estándar, el SDK de Android (aapt) genera automáticamente un conjunto de reglas para los recursos: aapt comprueba todos los archivos xml (incluido el manifiesto) para encontrar todas las actividades, servicios, vistas, etc. y generar las reglas necesarias para ellos. Las reglas generadas se pueden encontrar en app/build/intermediates/proguard-rules/<flavor>/aapt_rules.txt
. No necesita especificarlo usted mismo, Android Gradle Plugin agregará estas reglas automáticamente.

(Imagen de la presentación de Jeb Ware, enlace al final del artículo)
Configuraciones
Configurar Proguard es la parte más básica de trabajar con él y, al mismo tiempo, la más difícil. Una configuración incorrecta puede romper fácilmente la compilación de la aplicación y la propia aplicación en tiempo de ejecución. Todas las opciones de configuración disponibles se documentan detalladamente en apagado. sitio.
Entre todas las opciones, destacaría los 3 grupos más importantes:
- mantener reglas: todos los puntos de entrada posibles al programa. Reglas que le indican a Proguard qué clases o partes de clases deben mantenerse sin cambios o cuáles de las modificaciones son válidas para clases específicas.
- ajuste de optimización: indique qué optimizaciones son aceptables, cuántos ciclos de optimización deben realizarse.
- trabajar con advertencias, errores y depuración
Mantener las reglas
Este es un conjunto de opciones diseñadas para proteger su código del implacable Proguard. En su forma más general, esta regla se ve así:
-keep [,modifier,...] class_specification
keep
es la más común de estas opciones (hay otras), y le dice a Proguard que guarde la clase y todos sus miembros: campos y métodos.
class_specification
: una plantilla que apunta a la (s) clase (s) o sus partes (miembros de la clase). La vista general de la plantilla es muy grande, se puede ver fuera. documentación Puede contactarlo, pero en general, puede recordar que tenemos la oportunidad de componer una plantilla de estos componentes:
- seleccione todas las clases con un nombre específico, paquete
- seleccionar todas las clases que heredan / implementan ciertas clases / interfaces
- seleccionar todas las clases con modificadores específicos y / o anotaciones específicas
- seleccione todos los métodos con un nombre específico, modificadores, argumentos y valor de retorno
- seleccione todos los campos con un nombre específico, modificadores, de un tipo específico.
es posible usar comodines
Una vez más, esta no es una descripción estricta de la plantilla; es más bien una lista de las características que tenemos. Aquí hay algunos ejemplos:
-keep public class com.example.MyActivity
guardar clase com.example.MyActivity
-keep public class * extends android.app.Activity
guardar todas las clases públicas heredando android.app.Activity
-keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); }
encuentre todas las clases públicas que heredan android.view.View
y guarde 3 constructores con ciertos parámetros en ellos + todos los métodos públicos, con el modificador void
, cualquier argumento y un nombre que comience con set
. Todas las otras partes de la clase se pueden modificar.
-keep class com.habr.** { *; }
guardar todas las clases y todos sus contenidos en el paquete com.habr
modifiers
- además de la regla de mantenimiento:
includedescriptorclasses
: además de la clase / método / campo especificado, debe guardar todas las clases que aparecen en sus descriptores.includecode
: tampoco se puede tocar el contenido del método señalado por esta regla en particular.allowshrinking
: las clases a las que apunta esta regla no son semillas y se pueden eliminar, pero solo si no se usan en el programa en sí. Sin embargo, si después de la reducción de códigos este código permanece (debido al hecho de que alguien lo usa), es imposible optimizar / ofuscar este código.allowoptimization
: las clases a las que hace referencia esta regla solo se pueden optimizar, pero no se pueden eliminar ni ofuscar.allowobfuscation
: las clases a las que apunta esta regla solo se pueden ofuscar, pero no se pueden eliminar ni optimizar.
Además de keep
, hay algunas opciones más:
-keepclassmembers
: indica que los miembros de la clase deben guardarse si la clase en sí se conserva después de la reducción del código.
-keepclasseswithmembers
: indica que desea guardar clases cuyo contenido se encuentre dentro de la plantilla especificada. Por ejemplo, -keepclasseswithmembers class * { public <init>(android.content.Context); }
-keepclasseswithmembers class * { public <init>(android.content.Context); }
: guarda todas las clases que tienen un constructor público con un argumento de tipo Context
.
-keepnames
: abreviatura de -keep,allowshrinking
.
-keepclassmembernames
: abreviatura de -keepclassmembers,allowshrinking
.
keepclasseswithmembernames
- abreviatura de -keepclasseswithmembers,allowshrinking
.
Optimización de optimización
La opción más importante aquí es la bandera -dontoptimize
. Si está presente, no se realizará ninguna optimización y se ignorarán todas las demás opciones de optimización.
Hay muchas opciones de optimización, pero las siguientes son las más útiles para mí:
-optimizations optimization_filter
: enumera todas las formas que desea utilizar. Es mejor usar el conjunto especificado en proguard-android-optimize.txt
o un subconjunto del mismo. Puede encontrar una lista de todas las optimizaciones aquí .
-optimizationpasses n
- número de ciclos de optimización. Varios ciclos pueden mejorar el resultado. Al mismo tiempo, Proguard es lo suficientemente inteligente como para detener los ciclos si ve que el resultado no ha mejorado desde la última vez.
-assumenosideeffects class_specification
: indica que este método no tiene efectos secundarios y solo devuelve algún valor. Proguard eliminará las llamadas a este método si detecta que el resultado que devuelve no se utiliza. Quizás el uso más común de esta opción es eliminar todos los registros de depuración: -assumenosideeffects class android.util.Log { public static int d(...); }
-assumenosideeffects class android.util.Log { public static int d(...); }
-allowaccessmodification
: muestra todo lo que está oculto :) Una excelente opción que te permite deshacerte de un montón de métodos de acceso artificiales para clases anidadas. Solo funciona en conjunto con -repackageclasses
-repackageclasses
: le -repackageclasses
mover todas las clases a un paquete específico. Esto se aplica más a la ofuscación, pero al mismo tiempo, da buenos resultados en la optimización.
Otras opciones utiles
-dontwarn
y -dontnote
Proguard es muy inteligente y siempre informa lugares sospechosos durante el análisis del código, a veces son notas, a veces advertencias. Si su compilación no funciona con Proguard activado, asegúrese de leer todos los registros que produce, escribirá lo que salió mal y, muy probablemente, incluso le dirá cómo solucionarlo. Después de leer todos los mensajes, puede solucionar el problema o ignorar el mensaje de una de estas opciones si está seguro de que no hay ningún problema.
Por ejemplo, sucede que alguna biblioteca de Java usa clases de plataforma que no están en android.jar y Proguard le advertirá sobre esto. Si está seguro de que esta biblioteca funciona bien en un entorno Android, puede desactivar esta advertencia -dontwarn java.lang.management.**
-whyareyoukeeping class_specification
es una opción útil que imprimirá la razón por la cual Proguard decidió no tocar esta clase / método.
-verbose
: imprime registros más detallados y excepciones
-printconfiguration
: imprime una lista completa de opciones de todos los archivos de configuración que se utilizaron, incluidas las reglas de las bibliotecas y generadas a través de aapt.
-keepattributes SourceFile, LineNumberTable
: guarda la metainformación (nombres de archivo, numeración de líneas) para poder depurar código en el IDE y obtener un seguimiento de pila significativo. Asegúrese de agregar esta opción.
Practica
Esto suele suceder: enciende Proguard y te interrumpe todo el proyecto dando muchos errores. Muchos en este paso apagan Proguard e intentan no volver a él. Intentaré dar algunos consejos para facilitar este proceso de transición.
Decidir sobre los puntos de entrada de partida.
Si usted es un desarrollador de Android, todo es extremadamente elemental: solo seleccione una de las dos configuraciones estándar del SDK de Android: proguard-android.txt
o proguard-android-optimize.txt
, se encargarán de todo lo que debe permanecer intacto.
Verifica todas las bibliotecas
Recientemente, se distribuyen más y más bibliotecas con configuraciones de protección preparadas. Proguard puede mirar dentro del archivo, encontrar la configuración de la biblioteca y agregarla a otras opciones. Verifique cada biblioteca que use para dicha configuración.

(contenido del archivo aar de una de las bibliotecas)
Si utiliza los servicios de Google Play, entonces el complemento com.google.gms.google-services
seleccionará la configuración que necesita por su cuenta.
Si los autores de la biblioteca no empaquetan la configuración en el archivo, tal vez se cuidaron y escribieron las reglas en su sitio web, en la página del repositorio o en el archivo README. Intente encontrar la configuración usted mismo para la versión de la biblioteca que está utilizando.
Si no puede encontrar ninguna regla preparada en ningún lado, deberá leer los registros y resolver el problema individualmente. Lo más probable es que deba agregar reglas de mantenimiento para el código de la biblioteca que no funciona. O ignore los errores si no interfieren con el programa.
Inspecciona tu código
Sabes mejor qué código puedes enviar debajo del cuchillo, pero debes mirar cuidadosamente todos los lugares donde se usa la reflexión de todos modos:
- Class.forName (...) (la documentación promete que Proguard puede definir dicho código, sin embargo, ha habido casos, vale la pena verificarlo)
- Modelos / clases de entidad que se utilizan en serialización, mapeo. Todas las clases cuyos nombres de campo (a veces las clases mismas) son importantes para mantener (Gson, RealmIO, etc.)
- llamadas a bibliotecas nativas a través de JNI
Pruebas
Si una clase / método se usa solo en pruebas y en ningún otro lugar, Proguard eliminará este código. Esta es una situación común si tiene TDD :) Para este caso, tengo una configuración separada, donde agrego clases que aún no están integradas en el proyecto, no se usan en ninguna parte, pero que necesitan ser probadas.
En el complemento Gradle de Android, además de las instrucciones de proguardFiles
, todavía hay testProguardFiles
. Esta instrucción es necesaria para especificar las configuraciones que se aplicarán a la aplicación de prueba que se genera para probar su aplicación cuando ejecuta pruebas de instrumentación. Por lo general, esto se usa para lograr la misma optimización / ofuscación en ambos archivos apk para que no haya desincronización entre ellos. Enlace
Analizador de APK
Android Studio tiene una gran herramienta. Puede abrirlo a través de Buscar acción -> Analizar APK, o abriendo el archivo apk en Android Studio. El analizador muestra mucha información útil, pero ahora estamos interesados en el código. Para ver lo que finalmente se empaquetó en un archivo APK, debe seleccionar el archivo classes.dex

Por defecto, se le mostrará exactamente el código resultante que ha pasado los pasos de reducción y optimización. Sin embargo, puede hacer clic en el botón Cargar asignaciones de Proguard ... , agregar seeds.txt
y usage.txt
para ver el código que se ha eliminado.

Si Proguard por alguna razón modificó el código que necesita, búsquelo en el Analizador y seleccione Generar Proguard Keep Rule a través de RMB. Analyzer generará una selección de varias opciones para las reglas, desde la más general hasta la más específica, seleccione UNA de ellas.


Para autores de bibliotecas.
Si está creando una biblioteca de Android, puede agregar una configuración de protección para sus clientes de la siguiente manera:
buildTypes { release { consumerProguardFiles 'proguard-rules.pro' } }
En mi opinión, es mejor no optimizar celosamente y ofuscar su biblioteca, sino brindar esta oportunidad a sus clientes. Un buen tono es agregar a la configuración lo que los clientes aún tendrán que agregar si incluyen Proguard. Sin embargo, si aún desea agregar seguridad, es obvio que necesita proteger la API completa de su biblioteca de Proguard, incluidos los descriptores y las firmas.
R8, DexGuard y Redex
R8 es la nueva herramienta de Google para reemplazar el Proguard actual. Espera, no intentes olvidar todo lo que acabas de leer en el artículo, solo trátalo como el nuevo Proguard. Google promete mantener la API pública completa, para que todas las configuraciones funcionen como antes. El proyecto todavía está en beta, pero puedes probarlo tú mismo.
DexGuard es una utilidad paga de los desarrolladores de Proguard. Se puede usar juntos o en lugar de Proguard. Se argumenta que DexGuard puede hacer todo lo que Proguard puede hacer, pero mejor. Desafortunadamente, no tuve la oportunidad de probarlo, si alguien tiene experiencia, compártelo.
Redex es otro optimizador de dex de Facebook. Se informa que con él puede lograr hasta un 25% de aumento en la productividad y reducir el tamaño de la aplicación aplicando la herramienta al código ya procesado por Proguard.
En lugar de una conclusión
No tengas miedo de usar Proguard, no seas perezoso y pasa algún tiempo preparándote. Esto reducirá su tamaño, aumentará la velocidad del trabajo, que agregará la lealtad de sus usuarios. Al mismo tiempo, intente crear configuraciones efectivas de Proguard, no escriba reglas de "alfombra", de lo contrario, un enojado Jake Wharton vendrá a usted y lo regañará.

Recursos
Sitio web de Proguard . También hay información sobre DexGuard.
Varias reglas de ejemplo
R8
Grabar una presentación de cómo funciona Proguard con DroidCon
ProGuard efectivo mantiene reglas para la grabación de presentaciones de aplicaciones más pequeñas (Google I / O '18)
Instrucciones para habilitar y configurar Proguard para Android
Página Wiki
Redex