Reduce el tamaño de tu app

Los usuarios suelen evitar la descarga de apps que parecen muy pesadas, particularmente en mercados emergentes, donde la conexión 2G y 3G suele ser intermitente o los dispositivos se conectan a través de planes con límites de datos. En esta página, se describe cómo reducir el tamaño de tu app para aumentar la cantidad de usuarios que la descargan.

Sube tu app con Android App Bundles

Sube la app como Android App Bundle para reducir, inmediatamente, el tamaño de tu app cuando la publicas en Google Play. Android App Bundle es un formato de carga que incluye todos los recursos y el código compilado de tu app, pero delega la generación del APK y la firma a Google Play.

El modelo de entrega de apps de Google Play usa el paquete de aplicación para generar y entregar APKs optimizados para la configuración del dispositivo de cada usuario, de manera que solo descarguen el código y los recursos necesarios para ejecutar la app. Ya no tendrás que compilar, firmar ni administrar múltiples APKs para admitir diferentes dispositivos, y los usuarios podrán realizar descargas más pequeñas y optimizadas.

Google Play aplica una restricción de tamaño de descarga comprimida de 200 MB para las apps publicadas con paquetes de aplicaciones. Es posible usar tamaños más grandes con Play Feature Delivery y Play Asset Delivery, pero aumentar el tamaño de tu app puede afectar negativamente el éxito de la instalación y aumentar las desinstalaciones, por lo que te recomendamos que apliques los lineamientos que se describen en esta página para reducir el tamaño de descarga de tu app tanto como sea posible.

Comprende la estructura de APK

Antes de reducir el tamaño de tu app, es útil comprender la estructura de su archivo APK. El archivo APK consiste en un archivo ZIP que engloba todos los archivos que conforman la app, lo que incluye archivos de clase Java y de recursos, y uno que contiene recursos compilados.

Un APK incluye los siguientes directorios:

  • META-INF/: Contiene los archivos de firma CERT.SF y CERT.RSA, además del archivo de manifiesto MANIFEST.MF.
  • assets/: Contiene los elementos de la app, que esta puede recuperar a través de un objeto AssetManager.
  • res/: Contiene recursos que no están incluidos en resources.arsc.
  • lib/: Contiene el código compilado específico para la capa del software de un procesador. Este directorio contiene un subdirectorio para cada tipo de plataforma, como armeabi, armeabi-v7a, arm64-v8a, x86, x86_64 y mips.

Además, un APK contiene los siguientes archivos. El único objeto obligatorio es AndroidManifest.xml:

  • resources.arsc: Contiene recursos compilados. El archivo incluye el contenido XML de todas las configuraciones de la carpeta res/values/. La herramienta empaquetadora extrae el contenido XML, lo compila en formato binario y lo archiva. Dentro de este contenido, se incluyen cadenas de idioma y estilos, además de rutas al contenido que no está incluido directamente en el archivo resources.arsc, como imágenes y archivos de diseño.
  • classes.dex: Contiene las clases compiladas en el formato de archivo DEX que comprende la máquina virtual Dalvik/ART.
  • AndroidManifest.xml: Contiene el archivo de manifiesto principal de Android. En este archivo, se incluyen el nombre, la versión, los derechos de acceso y los archivos de la biblioteca mencionados de la app, y se utiliza el formato XML binario de Android.

Reduce el tamaño y la cantidad de recursos

El tamaño del APK influye en la velocidad de carga de la app, la cantidad de memoria que usa y la batería que consume. Para reducir el tamaño del APK, disminuye la cantidad de recursos que contiene y su tamaño. Específicamente, puedes quitar recursos que tu app ya no usa y, además, utilizar objetos Drawable escalables en lugar de archivos de imagen. En esta sección, se explican estos métodos y otras alternativas para que puedas reducir los recursos de tu app y el tamaño total del APK.

Quita recursos que no se usan

La herramienta lint, un analizador de código estático que se incluye en Android Studio, detecta los recursos de la carpeta res/ a los que el código no hace referencia. Si la herramienta lint detecta un recurso que posiblemente no se use en tu proyecto, muestra un mensaje como el que aparece a continuación:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
    to be unused [UnusedResources]

Es posible que las bibliotecas que agregues al código incluyan recursos que no se usen. Gradle puede quitar automáticamente los recursos por ti si habilitas shrinkResources en el archivo build.gradle.kts de la app.

Kotlin

android {
    // Other settings.

    buildTypes {
        getByName("release") {
            minifyEnabled = true
            shrinkResources = true
            proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro")
        }
    }
}

Groovy

android {
    // Other settings.

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Para usar shrinkResources, habilita la reducción de código. Durante el proceso de compilación, R8 primero quita el código que no se usa. Luego, el complemento de Android para Gradle quita los recursos que no se utilizan.

Si quieres obtener más información sobre la reducción de código y recursos, y sobre otras formas en que Android Studio te ayuda a reducir el tamaño del APK, consulta el artículo para reducir, ofuscar y optimizar tu app.

En el complemento de Android para Gradle 7.0 y versiones posteriores, puedes informar las configuraciones que admite tu app. Gradle le transmite esa información al sistema de compilación con la variante resourceConfigurations y la opción defaultConfig. Este sistema de compilación evita que aparezcan recursos de otras configuraciones no admitidas en el APK y, de esta forma, reduce su tamaño. Para obtener más información sobre esta función, consulta Cómo quitar recursos alternativos que no se usan.

Minimiza el uso de recursos de la biblioteca

Cuando desarrollas una app para Android, sueles utilizar bibliotecas externas para mejorar la usabilidad y versatilidad de la app. Por ejemplo, puedes establecer una referencia a AndroidX para mejorar la experiencia del usuario en dispositivos más antiguos. También puedes usar los Servicios de Google Play para recuperar traducciones automáticas del texto en tu app.

Si se diseña una biblioteca para un servidor o una computadora de escritorio, puede incluir varios objetos y métodos que no son necesarios para la app. Para incluir solamente las partes de la biblioteca que son necesarias, puedes editar sus archivos si la licencia te permite modificar la biblioteca. También puedes usar una biblioteca alternativa y optimizada para dispositivos móviles para agregar alguna funcionalidad específica a la app.

Decodificación de imágenes animadas nativas

En Android 12 (nivel de API 31), se expandió la API de ImageDecoder del NDK para decodificar todos los fotogramas y datos de tiempo de las imágenes que usan el GIF animado y formatos de archivo WebP animados.

Usa ImageDecoder en lugar de bibliotecas de terceros para reducir el tamaño del APK y aprovechar las actualizaciones futuras relacionadas con la seguridad y el rendimiento.

Para obtener más información sobre la API de ImageDecoder, consulta API reference y el ejemplo en GitHub.

Admite únicamente densidades específicas

Android admite diferentes densidades de pantalla, como las siguientes:

  • ldpi
  • mdpi
  • tvdpi
  • hdpi
  • xhdpi
  • xxhdpi
  • xxxhdpi

Aunque Android admite las densidades anteriores, no es necesario exportar los elementos de los cuales se generó una trama a cada una de ellas.

Si sabes que solo un pequeño porcentaje de los usuarios tiene dispositivos con densidades específicas, considera si es necesario agrupar esas densidades en la app. Si no incluyes recursos para una densidad de pantalla específica, Android ajustará automáticamente la escala de los recursos existentes que fueron diseñados originalmente para otras densidades de pantalla.

Si tu app solo necesita imágenes ajustadas a escala, puedes incluir una sola variante de la imagen en drawable-nodpi/ para ahorrar más espacio. Te recomendamos que incluyas al menos una variante de imagen xxhdpi en la app.

Para obtener más información sobre las densidades de pantalla, consulta Tamaños y densidades de pantalla.

Usa elementos de diseño

En algunas imágenes, no se necesita un recurso de imagen estática. En cambio, el framework puede diseñar dinámicamente la imagen durante el tiempo de ejecución. Los objetos Drawable (o <shape> en XML) pueden ocupar muy poco espacio en el APK. Además, los objetos Drawable de XML producen imágenes monocromáticas que cumplen con los lineamientos de Material Design.

Vuelve a usar recursos

Puedes incluir un recurso separado para variaciones de una imagen, por ejemplo, versiones en las que se modifique el tono, el matiz o la rotación. Sin embargo, te recomendamos que vuelvas a usar el mismo conjunto de recursos y que los personalices según sea necesario durante el tiempo de ejecución.

Android proporciona varias utilidades para cambiar el color de un elemento con los atributos android:tint y tintMode.

También puedes omitir recursos cuando se trata de la versión rotada de otro recurso. El siguiente fragmento de código proporciona un ejemplo en el cual un "Me gusta" se transforma en un "No me gusta". Para hacerlo, hay que rotar el centro de la imagen en 180°:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_thumb_up"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="180" />

Renderiza desde un código

También puedes reducir el tamaño del APK con el procesamiento a través de renderizaciones de tus imágenes. Este método permite liberar espacio gracias a que deja de ser necesario almacenar un archivo de imagen en el APK.

Procesa los archivos PNG

Con la herramienta aapt, se pueden optimizar los recursos de imagen que se encuentran en res/drawable/ con una compresión sin pérdidas durante el proceso de compilación. Por ejemplo, la herramienta aapt puede convertir un archivo PNG con color verdadero en el que no se necesitan más de 256 colores en un PNG de 8 bits con una paleta de colores. De este modo, la imagen tiene la misma calidad, pero el uso de memoria es menor.

aapt tiene las siguientes limitaciones:

  • La herramienta aapt no reduce los archivos PNG que se encuentran en la carpeta asset/.
  • Los archivos de imágenes deben tener 256 colores o menos para que la herramienta aapt pueda optimizarlas.
  • La herramienta aapt puede aumentar el tamaño de los archivos PNG que ya se comprimieron. Con el objeto de evitar este aumento, puedes usar la marca isCrunchPngs para inhabilitar este proceso para los archivos PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Groovy

        buildTypes.all { isCrunchPngs = false }
        

Comprime los archivos PNG y JPEG

Puedes reducir el tamaño de un archivo PNG sin perder la calidad de la imagen con herramientas como pngcrush, pngquant o zopflipng. Todas estas reducen el tamaño del archivo PNG y, a la vez, preservan la calidad perceptiva de la imagen.

La herramienta pngcrush es particularmente efectiva. Esta herramienta itera en todos los filtros PNG y parámetros zlib (reducción de tamaño) con una combinación de filtros y parámetros para comprimir la imagen. Luego, selecciona la configuración que produce la salida comprimida de menor tamaño.

Para comprimir archivos JPEG, puedes usar herramientas como packJPG y guetzli.

Usa el formato de archivo WebP

En lugar de usar archivos PNG o JPEG, puedes usar el formato de archivo WebP para las imágenes. El formato WebP proporciona una compresión con pérdidas y transparencia, como JPG y PNG, y puede proporcionar una mejor compresión que los archivos con formato JPEG o PNG.

Con Android Studio, puedes convertir imágenes GIF estáticas o BMP, JPG o PNG ya existentes a formato WebP. Para obtener más información, consulta Cómo crear imágenes WebP.

Usa gráficos vectoriales

Puedes usar gráficos vectoriales para crear íconos con resolución independiente y otro contenido multimedia escalable. Puedes usar estos gráficos para reducir notablemente el tamaño del APK. En Android, las imágenes vectoriales se representan como objetos VectorDrawable. Con un objeto VectorDrawable, un archivo de 100 bytes puede generar una imagen nítida del tamaño de la pantalla.

Sin embargo, se necesita considerablemente más tiempo para que el sistema renderice cada objeto VectorDrawable. Debido a que las imágenes más grandes tardarán más en aparecer en la pantalla, es recomendable que uses estos gráficos vectoriales solo para mostrar imágenes pequeñas.

Para obtener más información para trabajar con objetos VectorDrawable, consulta Elementos de diseño.

Usa gráficos vectoriales para imágenes animadas

No uses AnimationDrawable para crear animaciones por fotograma, ya que será necesario que incluyas un archivo de mapa de bits distinto para cada fotograma de la animación, con lo cual el tamaño del APK aumentará considerablemente.

En cambio, usa AnimatedVectorDrawableCompat para crear elementos de diseño vectoriales animados.

Reduce el código nativo y Java

Puedes usar los siguientes métodos para reducir el tamaño de la base de código nativo o Java en la app.

Quita el código que se generó innecesariamente

Asegúrate de comprender el impacto de cualquier código que se genere automáticamente. Por ejemplo, varias herramientas de búfer de protocolo generan una cantidad excesiva de métodos y clases, que pueden duplicar o triplicar el tamaño de la app.

Evita las enumeraciones

Una enumeración puede agregar entre 1.0 y 1.4 KB al archivo classes.dex de la app. En el caso de sistemas complejos y bibliotecas compartidas, estas adiciones podrían acumularse rápidamente. Te recomendamos que, si es posible, uses la anotación @IntDef y la reducción de código para evitar las enumeraciones y convertirlas en enteros. Este tipo de conversión conserva todos los beneficios de seguridad de las enumeraciones.

Reduce el tamaño de los objetos binarios nativos

Si tu app usa código nativo y NDK de Android, puedes optimizar el código para reducir el tamaño de la versión de actualización de la app. Para ello, hay dos técnicas útiles: quitar los símbolos de depuración y no extraer las bibliotecas nativas.

Quita los símbolos de depuración

Si la app está en desarrollo y todavía necesita depuración, es conveniente usar símbolos de depuración. Usa la herramienta arm-eabi-strip, que se proporciona en el NDK de Android, para quitar los símbolos de depuración innecesarios de las bibliotecas nativas. Después, podrás crear la compilación de lanzamiento.

Evita extraer bibliotecas nativas

Cuando compiles la versión de actualización de tu app, incluye en un paquete los archivos .so sin comprimir en el APK con la configuración de useLegacyPackaging en false del archivo build.gradle.kts de la app. Inhabilitar esta marca evita que PackageManager copie archivos .so del APK al sistema de archivos durante la instalación. Este método reduce el tamaño de las actualizaciones de la app.

Conserva varios APKs de menor tamaño

Tu APK puede incluir contenido que los usuarios descargan, pero que nunca usan, como idiomas adicionales o recursos según la densidad de la pantalla. Para garantizar que la descarga sea mínima para los usuarios, sube tu app en Google Play con Android App Bundles. Subir de paquetes de aplicaciones permite a Google Play generar y publicar APKs optimizados para la configuración del dispositivo de cada uno de los usuarios, de manera que solo tengan que descargar el código y los recursos necesarios para ejecutar tu app. No tendrás que compilar, firmar y administrar varios APKs para tener compatibilidad con diferentes dispositivos, y los usuarios podrán realizar descargas más pequeñas y optimizadas.

Si no vas a publicar la app en Google Play, puedes segmentarla en varios APKs, diferenciados por factores, como el tamaño de la pantalla o la compatibilidad con la textura de la GPU.

Cuando un usuario descarga la app, el dispositivo recibe el APK correcto en función de sus características y configuración. De esta forma, no recibe elementos para características que el dispositivo no incluye. Por ejemplo, si un usuario tiene un dispositivo hdpi, no necesita recursos xxxhdpi que podrías incluir para dispositivos con pantallas de mayor densidad.

Para obtener más información, consulta Cómo compilar varios APKs y Compatibilidad con varios APKs.