Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo optimizar tu velocidad de compilación

Los tiempos de compilación prolongados ralentizan el proceso de desarrollo. En esta página, se ofrecen algunas técnicas para ayudarte a resolver cuellos de botella en la velocidad de compilación.

El proceso general de mejora de la velocidad de compilación es el siguiente:

  1. Optimiza la configuración de tu compilación mediante algunos pasos que proporcionan beneficios inmediatos para la mayoría de los proyectos de Android Studio.
  2. Genera un perfil para tu compilación a fin de identificar y diagnosticar algunos de los cuellos de botella más complejos que pueden ser específicos de tu proyecto o estación de trabajo.

Cuando desarrollas tu app, debes implementar un dispositivo con Android 7.0 (nivel de API 24) o una versión posterior siempre que sea posible. En las versiones más recientes de la plataforma de Android, se implementaron mejores mecanismos para introducir actualizaciones en tu app, como Android Runtime (ART) y la compatibilidad nativa con varios archivos DEX.

Nota: Después de tu primera compilación limpia, probablemente observes que las compilaciones posteriores, limpias e incrementales, son mucho más rápidas (aun cuando no se use ninguna de las optimizaciones que se describen en esta página). Esto se debe a que el daemon de Gradle tiene un período de "calentamiento" en el que aumenta el rendimiento, fenómeno similar al de otros procesos de equipos virtuales Java (JVM).

Cómo optimizar la configuración de tu compilación

Sigue estas sugerencias para mejorar la velocidad de compilación de tu proyecto de Android Studio.

Cómo mantener tus herramientas actualizadas

Las herramientas de Android reciben optimizaciones de compilación y funciones nuevas prácticamente con todas las actualizaciones, y, para algunas de las sugerencias que encontrarás en esta página, se presupone que usas la última versión. Para aprovechar las últimas optimizaciones, mantén actualizado lo siguiente:

Cómo crear una variante de compilación para desarrollo

Muchas de las configuraciones que necesitas cuando preparas tu app para el lanzamiento no son necesarias durante el desarrollo. Cuando habilitas procesos de compilación innecesarios, las compilaciones incrementales y limpias se vuelven más lentas, por lo que debes configurar una variante de compilación que conserve solo las configuraciones de compilación que necesites para el desarrollo de tu app. En el siguiente ejemplo, se crean una variante "dev" y una variante "prod" (para las configuraciones de tu versión de lanzamiento):

android {
  ...
  defaultConfig {...}
  buildTypes {...}
  productFlavors {
    // When building a variant that uses this flavor, the following configurations
    // override those in the defaultConfig block.
    dev {
      // To avoid using legacy multidex when building from the command line,
      // set minSdkVersion to 21 or higher. When using Android Studio 2.3 or higher,
      // the build automatically avoids legacy multidex when deploying to a device running
      // API level 21 or higher—regardless of what you set as your minSdkVersion.
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
    }

    prod {
      // If you've configured the defaultConfig block for the release version of
      // your app, you can leave this block empty and Gradle uses configurations in
      // the defaultConfig block instead. You still need to create this flavor.
      // Otherwise, all variants use the "dev" flavor configurations.
    }
  }
}

Si en la configuración de tu compilación ya se usan variantes de productos para crear diferentes versiones de tu app, puedes combinar las configuraciones "dev" y "prod" con esos tipos usando dimensiones de variantes. Por ejemplo, si ya configuraste variantes "demo" y "full", puedes usar el siguiente ejemplo de configuración para crear variantes combinadas, como "devDemo" y "prodFull":

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Specifies the flavor dimensions you want to use. The order in which you
  // list each dimension determines its priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.

  flavorDimensions "stage", "mode"

  productFlavors {
    dev {
      dimension "stage"
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
      ...
    }

    prod {
      dimension "stage"
      ...
    }

    demo {
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }
  }
}

Cómo habilitar la sincronización de proyectos con una sola variante

Sincronizar tu proyecto con la configuración de compilación es un paso importante para que Android Studio pueda comprender la manera en que está estructurado tu proyecto. Sin embargo, en el caso de proyectos grandes, el proceso puede consumir mucho tiempo. Si tu proyecto usa múltiples variantes de compilación, ahora puedes optimizar las sincronizaciones del proyecto limitándolas solo a la variante que hayas seleccionado.

Debes usar Android Studio 3.3 o una versión posterior con el complemento de Gradle para Android 3.3.0 o una versión posterior a fin de habilitar esta optimización. La optimización está habilitada de forma predeterminada en todos los proyectos.

Para habilitarla manualmente, haz clic en File > Settings > Experimental > Gradle (Android Studio > Preferences > Experimental > Gradle en Mac) y selecciona la casilla de verificación Only sync the active variant.

Nota: Esta optimización es completamente compatible con proyectos que incluyen Java y lenguajes C++, y ofrece compatibilidad limitada con Kotlin. Cuando se habilita la optimización para proyectos con contenido de Kotlin, la sincronización de Gradle vuelve a usar variantes completas de forma interna.

Cómo evitar compilar recursos innecesarios

Evita compilar y empaquetar recursos que no vayas a probar (como localizaciones de idioma adicionales y recursos de densidad de pantalla). También puedes hacerlo especificando únicamente un recurso de idioma y una densidad de pantalla para la variante "dev", como se muestra en el siguiente ejemplo:

android {
  ...
  productFlavors {
    dev {
      ...
      // The following configuration limits the "dev" flavor to using
      // English stringresources and xxhdpi screen-density resources.
      resConfigs "en", "xxhdpi"
    }
    ...
  }
}

Cómo inhabilitar Crashlytics para tus compilaciones de depuración

Si no necesitas ejecutar un informe de Crashlytics, acelera tus compilaciones de depuración inhabilitando el complemento de la siguiente manera:

android {
  ...
  buildTypes {
    debug {
      ext.enableCrashlytics = false
    }
}

También debes inhabilitar el kit de Crashlytics en el tiempo de ejecución para las compilaciones de depuración cambiando la manera en la que inicializas la compatibilidad con Fabric en tu app, como se muestra a continuación:

Kotlin

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics.Builder()
        .core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
        .build()
        .also { crashlyticsKit ->
            Fabric.with(this, crashlyticsKit)
        }

Java

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics crashlyticsKit = new Crashlytics.Builder()
    .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
    .build();

Fabric.with(this, crashlyticsKit);

Cómo inhabilitar la generación automática de ID de compilación

Si deseas usar Crashlytics con tus compilaciones de depuración, puedes de todos modos acelerar las compilaciones incrementales evitando que Crashlytics actualice recursos de la app con su ID de compilación único durante cada compilación. Como este ID de compilación se almacena en un archivo de recurso al que hace referencia el manifiesto, si inhabilitas la generación automática de ID de compilación también podrás usar Apply Changes junto con Crashlytics para las compilaciones de depuración.

Para evitar que Crashlytics actualice automáticamente su ID de compilación, agrega lo siguiente a tu archivo build.gradle:

android {
  ...
  buildTypes {
    debug {
      ext.alwaysUpdateBuildId = false
    }
}

Para obtener más información sobre la optimización de tus compilaciones mientras usas Crashlytics, lee la documentación oficial.

Cómo usar valores de configuración de compilación estáticos con tu compilación de depuración

Usa siempre valores estáticos o no modificables para las propiedades que se incluyen en el archivo de manifiesto o los archivos de recursos para tu tipo de compilación de depuración.

Por ejemplo, para usar códigos de versión dinámicos, nombres de versión, recursos o cualquier otra lógica de compilación que modifique el archivo de manifiesto, se requiere una compilación del APK completa cada vez que deseas ejecutar un cambio, aunque en otras circunstancias la modificación solo hubiera requerido un intercambio directo. Si tu configuración de compilación requiere esas propiedades dinámicas, debes aislarlas de las variantes de tu compilación de lanzamiento y conservar valores estáticos para tus compilaciones de depuración, como se muestra en el archivo build.gradle a continuación.

int MILLIS_IN_MINUTE = 1000 * 60
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE

android {
    ...
    defaultConfig {
        // Making either of these two values dynamic in the defaultConfig will
        // require a full APK build and reinstallation because the AndroidManifest.xml
        // must be updated.
        versionCode 1
        versionName "1.0"
        ...
    }

    // The defaultConfig values above are fixed, so your incremental builds don't
    // need to rebuild the manifest (and therefore the whole APK, slowing build times).
    // But for release builds, it's okay. So the following script iterates through
    // all the known variants, finds those that are "release" build types, and
    // changes those properties to something dynamic.
    applicationVariants.all { variant ->
        if (variant.buildType.name == "release") {
            variant.mergedFlavor.versionCode = minutesSinceEpoch;
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
        }
    }
}

Cómo usar versiones de dependencias estáticas

Cuando declares dependencias en tus archivos build.gradle, deberás evitar usar números de versión con un signo más al final, como 'com.android.tools.build:gradle:2.+'. El uso de números de versión dinámicos puede generar actualizaciones de versión inesperadas, dificultar la resolución de diferencias de versión y ralentizar las compilaciones debido a que Gradle busca actualizaciones. Como alternativa, debes usar números de versión estáticos o no modificables.

Cómo habilitar el modo sin conexión

Si tu conexión de red es lenta, los tiempos de compilación pueden verse afectados cuando Gradle intente usar recursos de la red para resolver dependencias. Puedes indicar a Gradle que evite usar recursos de red y use solo los artefactos almacenados en caché a nivel local.

Para usar Gradle sin conexión cuando realices compilaciones con Android Studio, haz lo siguiente:

  1. Abre la ventana Preferences haciendo clic en File > Settings (en Mac, Android Studio > Preferences).
  2. En el subpanel izquierdo, haz clic en Build, Execution, Deployment > Gradle.
  3. Selecciona la casilla de verificación Offline work.
  4. Haz clic en Apply o en OK.

Si realizas la compilación desde la línea de comandos, pasa la opción --offline.

Cómo crear módulos de biblioteca

Busca en tu app código que puedas convertir en un módulo de biblioteca de Android. La modularización de tu código de esta manera permite que el sistema de compilación compile solo los módulos que modifiques y almacene en caché los resultados para compilaciones futuras. También aporta más eficacia a la ejecución de proyectos paralelos (cuando habilitas esa optimización).

Cómo crear tareas para lógica de compilación personalizada

Una vez que crees un perfil para la compilación, si en este se muestra que una fracción relativamente larga del tiempo de compilación se dedica a la etapa de "configuración de proyectos", revisa tus secuencias de comandos de build.gradle y busca código que puedas incluir en una tarea de Gradle personalizada. Si se traslada parte de la lógica de compilación a una tarea, que se ejecutará únicamente cuando sea necesario, los resultados se pueden almacenar en caché para compilaciones futuras y la lógica de compilación reunirá las condiciones con el objetivo de ejecutarse en paralelo (si habilitas la ejecución de objetos en paralelo). Para obtener más información, lee la documentación oficial de Gradle.

Sugerencia: Si tu compilación incluye una gran cantidad de tareas personalizadas, te recomendamos ordenar tus archivos build.gradle creando clases de tareas personalizadas. Agrega tus clases al directorio project-root/buildSrc/src/main/groovy/; Gradle los incluirá automáticamente en la ruta de clase para todos los archivos build.gradle de tu proyecto.

Cómo convertir imágenes a WebP

WebP es un formato de archivo de imagen que proporciona compresión con pérdida (como JPEG) y transparencia (como PNG), pero puede ofrecer mejor compresión que estos otros dos formatos. Reducir los tamaños de los archivos de imagen sin necesidad de realizar compresión de tiempo de compilación puede acelerar tus compilaciones, en particular, si tu app usa una gran cantidad de recursos de imagen. No obstante, puedes observar un pequeño incremento en el uso de la CPU del dispositivo mientras se descomprimen las imágenes WebP. Con Android Studio, puedes convertir tus imágenes a WebP con facilidad.

Cómo inhabilitar la compresión de PNG

Si no puedes (o no deseas) convertir tus imágenes PNG a WebP, puedes acelerar tu compilación mediante la inhabilitación de la compresión automática de imágenes cada vez que compilas tu app. Si usas un complemento de Android 3.0.0 o posterior, la compresión de PNG está inhabilitada de forma predeterminada solo para el tipo de compilación "debug". Si quieres inhabilitar esta optimización para otros tipos de compilación, agrega lo siguiente a tu archivo build.gradle:

android {
    buildTypes {
        release {
            // Disables PNG crunching for the release build type.
            crunchPngs false
        }
    }

// If you're using an older version of the plugin, use the
// following:
//  aaptOptions {
//      cruncherEnabled false
//  }
}

Debido a que los tipos de compilación o las variantes de productos no definen esta propiedad, deberás fijarla manualmente en true cuando compiles la versión de lanzamiento de tu app.

Cómo habilitar la caché de compilación

La caché de compilación guarda determinada información de salida que genera el complemento de Android para Gradle cuando compila tu proyecto (como AAR sin empaquetar y dependencias remotas previamente convertidas a archivos Dex). Tus compilaciones limpias son mucho más rápidas mientras se usa la caché, ya que el sistema de compilación puede simplemente reutilizar esos archivos almacenados en caché, en compilaciones posteriores, en lugar de volver a crearlos.

Los proyectos nuevos que usan el complemento de Android 2.3.0 y versiones posteriores habilitan la caché de compilación de forma predeterminada (a menos que inhabilites la caché de compilación de forma explícita). Para obtener más información, lee Cómo acelerar compilaciones limpias con la caché de compilación.

Cómo usar procesadores de anotaciones graduales

La versión 3.3.0 del complemento de Gradle para Android y las versiones posteriores mejoran la compatibilidad con el procesamiento de anotaciones incrementales. Por lo tanto, a fin de mejorar la velocidad de las compilaciones graduales, debes actualizar el complemento de Gradle para Android y utilizar solo procesadores de anotación graduales siempre que sea posible.

Nota: Esta función es compatible con Gradle 4.10.1 y sus versiones posteriores, excepto Gradle 5.1 (consulta el problema de Gradle número 8194).

Para comenzar, consulta la siguiente lista de procesadores de anotaciones populares que admiten el procesamiento de anotaciones incremental. La lista completa está disponible en Estado de compatibilidad en los procesadores de anotaciones populares. Es posible que algunos de los procesadores de anotaciones requieran pasos adicionales para habilitar la optimización, así que asegúrate de leer la documentación de cada uno.

Además, si usas Kotlin en tu app, debes usar kapt 1.3.30 y versiones posteriores si deseas admitir procesadores de anotaciones incrementales para tu código de Kotlin. Asegúrate de leer la documentación oficial para saber si necesitas habilitar manualmente este comportamiento.

Ten en cuenta que, si tienes que usar uno o más procesadores de anotaciones que no admiten compilaciones graduales, el procesamiento de anotaciones no será incremental. Sin embargo, aunque el proyecto use kapt, la compilación de Java aún será incremental.

Cómo generar un perfil para tu compilación

Los proyectos más grandes o aquellos que implementan una gran cantidad de lógica de compilación predeterminada pueden exigir que indagues más en el proceso de compilación a fin de detectar cuellos de botella. Puedes hacerlo generando perfiles sobre el tiempo que Gradle tarda en ejecutar cada etapa del ciclo de vida de la compilación y cada tarea de compilación. Por ejemplo, si tu perfil de compilación muestra que Gradle tarda mucho en configurar el proyecto, esto puede sugerir que necesitas quitar lógica de compilación personalizada de la etapa de configuración. Además, si la tarea mergeDevDebugResources consume una gran cantidad de tiempo de compilación, esto puede indicar que necesitas convertir tus imágenes a WebP o inhabilitar la compresión de PNG.

Si usas Android Studio 4.0 o versiones posteriores, la mejor manera de investigar los problemas de rendimiento de compilación es usar Build Analyzer.

Cómo generar un perfil para tu compilación desde la línea de comandos

Si no usas Android Studio, la solución de problemas de la velocidad de compilación, en general, implica ejecutar tu compilación desde la línea de comandos con la generación de perfiles habilitada, realizar algunos ajustes en la configuración de la compilación y generar más perfiles para observar los resultados de los cambios.

Para generar y ver un perfil de compilación, realiza los siguientes pasos:

  1. Abre una terminal de línea de comandos en la raíz de tu proyecto.
  2. Realiza una compilación limpia ingresando el siguiente comando. A medida que generes el perfil de tu compilación, deberás realizar una compilación limpia entre cada compilación de la que generes perfiles, ya que Gradle omite tareas cuando las entradas de estas (como el código fuente) no cambian. De este modo, una segunda compilación sin cambios en las entradas siempre se ejecuta más rápido porque las tareas no se vuelven a ejecutar. Por lo tanto, ejecutar la tarea clean entre tus compilaciones garantiza la generación de un perfil del proceso de compilación completo.
    // On Mac or Linux, run the Gradle wrapper using "./gradlew".
    gradlew clean
    
  3. Ejecuta una compilación de depuración de una de tus variantes de productos, como la variante "dev", con las siguientes marcas:
    gradlew --profile --offline --rerun-tasks assembleFlavorDebug
    
    • --profile: Habilita la generación de perfiles.
    • --offline: Evita que Gradle obtenga dependencias en línea. Esto garantiza que las demoras provocadas por Gradle cuando intenta actualizar tus dependencias no interfieran en los datos de la generación de perfiles. Para poder asegurarte de que Gradle haya descargado y almacenado en caché tus dependencias, es necesario que hayas compilado tu proyecto una vez.
    • --rerun-tasks: Hace que Gradle vuelva a ejecutar todas las tareas e ignore las optimizaciones de tareas.
  4. Figura 1: Vista del proyecto que indica la ubicación de los informes del perfil

    Una vez que finalice la compilación, usa la ventana Project para acceder al directorio project-root/build/reports/profile/ (como se muestra en la figura 1).

  5. Haz clic con el botón derecho en el archivo profile-timestamp.html y selecciona Open in Browser > Default. El informe debería ser similar al que se muestra en la figura 2. Puedes inspeccionar cada pestaña del informe para obtener información sobre tu compilación. Por ejemplo, en la pestaña Task Execution se muestra el tiempo que Gradle tardó en ejecutar cada tarea de compilación.

    Figura 2: Visualización de un informe en un navegador

  6. Opcional: Antes de realizar cambios en la configuración de tu proyecto o compilación, repite el comando del paso 3, pero omite la marca --rerun-tasks. Debido a que Gradle intenta ahorrar tiempo no volviendo a ejecutar tareas cuyas entradas no cambiaron (se indican como UP-TO-DATE en la pestaña Task Execution del informe, como se muestra en la figura 3), puedes identificar las tareas en ejecución que no deberían estar activas. Por ejemplo, si no se marca :app:processDevUniversalDebugManifest como UP-TO-DATE, esto puede sugerir que la configuración de tu compilación actualiza el manifiesto de forma dinámica con cada compilación. No obstante, algunas tareas se deben ejecutar durante cada compilación, como :app:checkDevDebugManifest.

    Figura 3: Visualización de los resultados de ejecución de tareas

Ahora que tienes un informe de perfil de compilación, puedes inspeccionar la información de cada pestaña del informe para comenzar a buscar oportunidades de optimización. Para algunas configuraciones de la compilación, se requiere experimentación, ya que los beneficios pueden diferir entre proyectos y estaciones de trabajo. Por ejemplo, en proyectos con una gran base de código, es posible aprovechar la reducción de código a fin de quitar el código no utilizado y reducir el tamaño del APK. No obstante, es posible lograr más beneficios para proyectos más pequeños si se inhabilita el código por completo. Además, aumentar el tamaño del montón de Gradle (mediante org.gradle.jvmargs) puede afectar negativamente el rendimiento en equipos con poca memoria.

Después de realizar un cambio en la configuración de tu compilación, observa los resultados de este repitiendo los pasos anteriores y generando un nuevo perfil de compilación. Por ejemplo, en la figura 4 se muestra un informe para el mismo ejemplo de app después de aplicar algunas de las optimizaciones básicas descritas en esta página.

Figura 4: Visualización de un informe nuevo después de optimizar la velocidad de compilación

Sugerencia: Si buscas una herramienta de generación de perfiles más eficaz, considera usar el generador de perfiles de código abierto de Gradle.