Skip to content

Most visited

Recently visited

navigation

Configurar apps con métodos de más de 64K

A medida que la plataforma Android continuó creciendo, lo mismo sucedió con el tamaño de las apps de Android. Cuando tu app y las bibliotecas a las que hace referencia alcanzan un tamaño determinado, se producen errores de compilación que indican que tu app alcanzó un límite de la arquitectura de compilación de la app de Android. Las versiones anteriores del sistema de compilación informan este error de la siguiente manera:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

Las versiones más recientes del sistema de compilación de Android muestran un error diferente, lo cual indica el mismo problema:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

Ambas condiciones de error muestran un número común: 65536. Este número es importante porque representa el número total de referencias que el código puede invocar dentro de un mismo archivo de código de byte Dalvik Executable (DEX). En esta página se explica la manera de superar esta limitación mediante la habilitación de una configuración de app conocida como MultiDex, que permite que tu app compile y lea varios archivos DEX.

Acerca del límite de referencia de 64K

Los archivos de las apps de Android (APK) contienen archivos de códigos de byte ejecutables en forma de archivos Dalvik Executable (DEX), que contienen el código compilado empleado para ejecutar tu app. La especificación de Dalvik Executable limita la cantidad total de métodos a los que se puede hacer referencia en un archivo Dex a 65 536, incluidos los métodos del framework de Android, de biblioteca y de tu propio código. En el contexto de la informática, el término Kilo, K, denota 1024 (o 2^10). Debido a que 65 536 es igual a 64 X 1024, este límite se denomina “límite de referencia de 64K”.

Compatibilidad de MultiDex con versiones anteriores a Android 5.0

Las versiones de la plataforma anteriores a Android 5.0 (nivel de API 21) usan el tiempo de ejecución de Dalvik para ejecutar código de apps. En forma predeterminada, Dalvik limita las apps a un único archivo de código de byte classes.dex por APK. Para evitar esta limitación, puedes usar la biblioteca de compatibilidad de MultiDex, que forma parte del archivo Dex principal de tu app y luego administra el acceso a los archivos Dex adicionales y al código que contienen.

Nota: Si tu proyecto está configurado para MultiDex con minSdkVersion 20 o una versión anterior, y tus implementaciones están destinadas a dispositivos con Android 4.4 (nivel de API 20) o versiones anteriores, Android Studio inhabilita Instant Run.

Compatibilidad de MultiDex con Android 5.0 y versiones posteriores

Android 5.0 (nivel de API 21) y las versiones posteriores usan un tiempo de ejecución denominado ART, que admite de manera nativa la carga de varios archivos DEX desde archivos APK. Durante el tiempo de instalación de la app, ART lleva a cabo una compilación previa que realiza un escaneo en busca de archivos classesN.dex y los compila en un único archivo .oat para que se ejecute en el dispositivo Android. De esta manera, si tu minSdkVersion es la 21 o una posterior, no necesitas la biblioteca de compatibilidad de MultiDex.

Para obtener más información sobre el tiempo de ejecución de Android 5.0, consulta ART y Dalvik.

Nota: Cuando usas Instant Run, si la minSdkVersion de tu app se halla fijada en 21 o un valor superior, Android Studio configura tu app para MultiDex automáticamente. Debido a que Instant Run solo funciona con la versión de depuración de tu app, debes de todos modos configurar tu compilación de lanzamiento para MultiDex si deseas evitar el límite de 64K.

Evita el límite de 64K

Antes de configurar tu app para habilitar el uso de 64K o más referencias de métodos, debes tomar medidas para reducir la cantidad total de referencias a las que llama el código de tu app, como los métodos definidos por el código de esta o las bibliotecas incluidas. Las siguientes estrategias pueden ayudarte a evitar alcanzar el límite de referencia de DEX:

Estas técnicas pueden ayudarte a evitar la necesidad de habilitar MultiDex en tu app y, al mismo tiempo, reducir el tamaño general de tu APK.

Configurar tu app para MultiDex

Para configurar tu proyecto de app de modo que use una configuración de MultiDex, debes hacer las siguientes modificaciones, según la versión mínima de Android que admita tu app.

Si tu minSdkVersion se halla fijada en 21 o un valor superior, lo único que debes hacer es establecer multiDexEnabled en true en tu archivo build.gradle de nivel de módulo, como se muestra a continuación:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 25
        multiDexEnabled true
    }
    ...
}

Sin embargo, si tu minSdkVersion se halla fijada en 20 o un valor inferior, debes usar la biblioteca de compatibilidad de MultiDex, como se indica a continuación:

Cuando compilas tu app, las herramientas de compilación de Android crean un archivo DEX primario (classes.dex) y archivos DEX de respaldo (classes2.dex, classes3.dex, etc.) según sea necesario. El sistema de compilación luego empaqueta todos los archivos DEX en tu APK.

En el tiempo de ejecución, las API de MultiDex usan un cargador de clase especial para buscar tus métodos en todos los archivos DEX disponibles (en lugar de hacerlo únicamente en el archivo classes.dex principal).

Limitaciones de la biblioteca de compatibilidad de MultiDex

La biblioteca de compatibilidad de MultiDex tiene algunas limitaciones conocidas que debes tener en cuenta y para las cuales debes realizar pruebas cuando la incorpores en la configuración de compilación de tu app:

Declarar las clases requeridas en el archivo DEX primario

Al compilar cada archivo DEX para una app MultiDex, las herramientas de compilación toman decisiones complejas para determinar las clases que se necesitan en el archivo DEX primario, de modo que tu app pueda iniciarse con éxito. Si no se suministra alguna de las clases requeridas durante el inicio en el archivo DEX primario, tu app se bloquea con el error java.lang.NoClassDefFoundError.

Esto no sucederá si accedes al código directamente desde el código de la app, ya que las herramientas de compilación reconocen las rutas de acceso de ese código. Sin embargo, puede suceder cuando las rutas de acceso del código son menos visibles; por ejemplo, cuando una de las bibliotecas usadas posee dependencias complejas. Por ejemplo, si el código usa introspección o invocación de métodos Java de código nativo, es posible que no se reconozcan esas clases como se requiere en el archivo DEX primario.

Entonces, si recibes java.lang.NoClassDefFoundError, debes especificar manualmente estas clases adicionales según sea necesario en el archivo DEX primario, para lo cual debes declararlas con el multiDexKeepFile o la propiedad multiDexKeepProguard en tu tipo de compilación. Si se hace coincidir una clase, ya sea en el multiDexKeepFile o en el archivo multiDexKeepProguard, esta se agrega al archivo DEX primario.

Propiedad multiDexKeepFile

El archivo que especificas en multiDexKeepFile debe contener una clase por línea, en el formato com/example/MyClass.class. Por ejemplo, puedes crear un archivo denominado multidex-config.txt parecido a este:

com/example/MyClass.class
com/example/MyOtherClass.class

Luego, puedes declarar ese archivo para un tipo de compilación, como se indica a continuación:

android {
    buildTypes {
        release {
            multiDexKeepFile file 'multidex-config.txt'
            ...
        }
    }
}

Recuerda que Gradle lee las rutas de acceso relativas al archivo build.gradle, por lo cual el ejemplo anterior funciona si multidex-config.txt está en el mismo directorio que el archivo build.gradle.

Propiedad multiDexKeepProguard

El archivo multiDexKeepProguard usa el mismo formato que Proguard y admite toda la gramática de Proguard. Para obtener más información sobre el formato y la gramática de Proguard, consulta la sección sobre Opciones de Keep del manual de Proguard.

El archivo que especifiques en multiDexKeepProguard debe incluir opciones de -keep en cualquier sintaxis de ProGuard válida. Por ejemplo, -keep com.example.MyClass.class. Puedes crear un archivo denominado multidex-config.pro parecido a este:

-keep class com.example.MyClass
-keep class com.example.MyClassToo

Si deseas especificar todas las clases en un paquete, el archivo tendrá el siguiente aspecto:

-keep class com.example.** { *; } // All classes in the com.example package

Luego, puedes declarar ese archivo para un tipo de compilación, como se indica a continuación:

android {
    buildTypes {
        release {
            multiDexKeepProguard 'multidex-config.pro'
            ...
        }
    }
}

Optimizar MultiDex en compilaciones de desarrollo

Una configuración de MultiDex requiere un tiempo de procesamiento de compilaciones mucho mayor, ya que el sistema de compilación debe tomar decisiones complejas sobre las clases que deben incluirse en el archivo DEX primario y las que pueden incluirse en los archivos DEX secundarios. Por este motivo, las compilaciones incrementales que usan MultiDex generalmente tardan más tiempo y posiblemente pueden desacelerar tu proceso de desarrollo.

A fin de reducir los tiempos de compilación más extensos para la salida de MultiDex, usa productFlavors para crear dos variantes de compilación: una clase de desarrollo y una clase de lanzamiento con diferentes valores para minSdkVersion.

Para la clase de desarrollo, fija minSdkVersion en 21. Esta configuración habilita una función de compilación denominada pre-dexing, que genera una salida de MultiDex mucho más rápida mediante un formato ART disponible únicamente en Android 5.0 (nivel de API 21) y versiones posteriores. Para la clase de versión, aplica a la minSdkVersion la configuración que corresponda para tu nivel mínimo actual de compatibilidad. Esta configuración genera un APK MultiDex compatible con más dispositivos, pero tarda más tiempo en compilarse.

En el siguiente ejemplo de configuración de compilación se demuestra la manera de configurar tipos en el archivo de compilación de Gradle:

android {
    defaultConfig {
        ...
        multiDexEnabled true
    }
    productFlavors {
        dev {
            // Enable pre-dexing to produce an APK that can be tested on
            // Android 5.0+ without the time-consuming DEX build processes.
            minSdkVersion 21
        }
        prod {
            // The actual minSdkVersion for the production version.
            minSdkVersion 14
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                                                 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile 'com.android.support:multidex:1.0.1'
}

Una vez completado el cambio de configuración, puedes usar la variante devDebug de tu app para las compilaciones incrementales; esta combina los atributos de la clase de producto dev y el tipo de compilación debug. De esta manera, se crea una app depurable con MultiDex habilitado y proguard inhabilitado (porque minifyEnabled es false en forma predeterminada). Con esta configuración, el complemento de Android para Gradle hace lo siguiente:

  1. Implementa pre-dexing: compila cada módulo de app y cada dependencia como un archivo DEX separado.
  2. Incluye cada archivo DEX en el APK sin modificación (sin reducir el código).
  3. Lo que es más importante, los archivos DEX del módulo no se combinan; por lo tanto, se evita el cálculo de ejecución larga para determinar el contenido del archivo DEX primario.

Esta configuración da como resultado compilaciones incrementales rápidas, ya que solo los archivos DEX de los módulos modificados se recalculan y se vuelven a empaquetar durante compilaciones posteriores. Sin embargo, el APK de estas compilaciones solo se puede usar para hacer pruebas en dispositivos con Android 5.0. No obstante, al implementar la configuración como una clase, conservas la capacidad de realizar compilaciones normales con el nivel de API mínimo adecuado para la versión y con reducción de código de ProGuard.

También puedes compilar las otras variantes; entre ellas, una compilación de variante prodDebug, que tarda más tiempo en compilarse, pero se puede usar para hacer comprobaciones fuera del desarrollo. Dentro de la configuración mostrada, la variante prodRelease sería la prueba final y la versión de lanzamiento. Para obtener más información sobre el uso de variantes de compilación, consulta la sección Configurar variantes de compilación.

Sugerencia: Ahora que tienes diferentes variantes de compilación para diferentes necesidades de MultiDex, también puedes proporcionar un archivo de manifiesto diferente para cada variante (de modo que solo la variante para el nivel de API 20 y niveles anteriores cambie el nombre de la etiqueta <application>) o bien crear una subclase de Application diferente para cada variante (de modo que solo la variante para el nivel de API 20 y niveles inferiores extienda la clase MultiDexApplication o invoque MultiDex.install(this)).

Comprobar las apps de MultiDex

Cuando se escriben pruebas de instrumentación para apps de MultiDex, no se requieren configuraciones adicionales.AndroidJUnitRunner admite MultiDex desde el primer momento siempre que uses MultiDexApplication o anules el método attachBaseContext() en tu objeto Application personalizado e invoques MultiDex.install(this) para habilitar MultiDex.

Alternativamente, puedes anular el método onCreate() en AndroidJUnitRunner:

public void onCreate(Bundle arguments) {
    MultiDex.install(getTargetContext());
    super.onCreate(arguments);
    ...
}

Nota: Actualmente no se admite el uso de MultiDex para crear un APK de prueba.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.