Android: mi aplicación es demasiado grande y da "No se puede ejecutar dex: método de ID no está en : 65536"?

Estoy intentando integrar mi aplicación con Box, Dropbox y Google Drive. Todos los 3 de estos servicios requieren un número de tarros de terceros. Además, mi aplicación ya requiere unos pocos frascos de terceros. Ahora, cuando intento ejecutar mi aplicación desde eclipse, obtengo el siguiente error:

No se puede ejecutar dex: método ID no está en [0, 0xffff]: 65536 Error en la conversión al formato Dalvik: No se puede ejecutar dex: método ID no está en [0, 0xffff]: 65536

Parece que este error se produce porque mi aplicación tiene demasiados métodos. Estoy bastante seguro de que la mayor parte de estos métodos son de los frascos de terceros, por lo que es poco realista tratar de resolver esto mediante la simplificación de mi código. Encontré estas dos sugerencias en línea.

  1. Agregue dex.force.jumbo=true a project.properties (y use la versión 21 de adt). Hice esto pero todavía consigo el error.

  2. Utilice múltiples archivos dex como se explica aquí: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html . Esto parece ser la única opción, pero no entiendo cómo se aplica en mi caso. El problema es que los servicios como Drive tienen demasiadas dependencias. ¿Esta solución no requeriría que yo modificara el origen de la unidad para usar inflexión cuando se refiere a sus dependencias? (Esto claramente no es una opción).

  3. Use proguard para reducir el código / métodos no utilizados. Exportar mi aplicación con proguard funciona, y la integración del servicio de documentos funciona como se esperaba en un dispositivo> 4.0. Sin embargo, los errores classnotfound se lanzan al probar en un dispositivo 2.3.

Por lo tanto, estoy esperando algunos consejos sobre este tema. ¿Es la opción 2 una solución para mi caso? ¿Hay otra solución que debo considerar?

También puede desarrollar uno o más de estos como un complemento para su aplicación principal, en forma de un APK aparte disponible para su descarga. Ese APK expondría algún componente que la aplicación principal utilizaría – ya que no sé la naturaleza de su integración con estos servicios, no puedo hacer una recomendación más específica sobre eso. Utilizaría su propia signature nivel personalizado <permission> para asegurar las comunicaciones entre las dos aplicaciones. Y, como un bono, si el uso de la biblioteca de terceros agrega requisitos para permisos adicionales, solo necesitaría esos permisos en el complemento APK, manteniendo su APK principal más pequeño.

La VM de Dalvik puede tener un máximo de 65536 métodos por archivo dex, debido a que el conjunto de instrucciones de bytecode no tiene una forma de referirse a los números de método que requieren más de 16 bits (como lo señaló @danfuzz en los comentarios).

Si bien es posible solucionar esto utilizando múltiples archivos dex, Facebook encontró otra solución que podrían implementar en su aplicación para resolver el problema.

*** NUEVO **** Todas las otras respuestas están ahora anticuadas. Esta es la nueva solución

Android 5.0 y superior

El soporte multi-dex se incluye automáticamente. De los documentos:

Android 5.0 y versiones superiores usan un tiempo de ejecución llamado ART que soporta de forma nativa la carga de múltiples archivos dex de los archivos APK de la aplicación. ART realiza la precompilación en el momento de la instalación de la aplicación, que busca los archivos .dex de clases (..N) y los compila en un único archivo .oat para su ejecución por el dispositivo Android. Para obtener más información sobre el tiempo de ejecución de Android 5.0, consulte Presentación de ART.

Debajo de Android 5.0

Simplemente agregue la herramienta de soporte de mult-dex para Android a su versión de gradle:

 android { compileSdkVersion 21 buildToolsVersion "21.1.0" defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling multidex support. multiDexEnabled true } ... } dependencies { compile 'com.android.support:multidex:1.0.0' } 

Véase vm / LinearAlloc.c y puede encontrar este código: (5MiB en Android 2.3.3, 8MiB después de Android 4.0 como mi investigación)

#define DEFAULT_MAX_LENGTH (5 * 1024 * 1024)

LinearAllocHdr * pHdr;

PHdr-> mapLength = DEFAULT_MAX_LENGTH;

Supongo que la 'corrección de Facebook' es la edición de esta memoria mediante el uso de C puntero nativo. IMHO LinearAlloc problema y este problema de identificación de método es cosa diferente.

Me enfrenté a este tema recientemente. Después de revisar la web para una implementación más detallada, me di cuenta de que no había mucho más que:

Me di cuenta de que el problema no era necesariamente que había demasiados métodos en mi código, pero que el dex completo de mi código y otras bibliotecas era el problema. Por lo tanto, si podría compilar mi código contra las bibliotecas, pero no incluirlas en el classes.dex , y luego dex las bibliotecas por separado, y luego ponerlo todo en tiempo de ejecución debería funcionar. El único problema que queda por resolver es el cargador de clases, que Facebook mencionó de pasada.

Así que con un poco de reflexión y un código de Groovy, creo que surgió con una forma relativamente estable de empaquetar las bibliotecas y el código de la aplicación en archivos dex separados.

https://gist.github.com/nickcaballero/7045993

La mayoría de los problemas con el límite del método de 65k están relacionados con el uso de los servicios mastodónicos de Google Play en sus aplicaciones. Recientemente, puede obtener más granularidad al usarlo.

Siguiendo esta guía , sólo puede utilizar las piezas que desee. Probablemente esto solucionará el problema, evitando algunos trucos de magia negra, o usando multiDex. Por ejemplo, si sólo desea que Google Maps en su aplicación (y no está utilizando anuncios, cartera, desgaste de Google, análisis, etc …), utilizar toda la dependencia es una pérdida de tiempo / espacio. Puedes usarlo de esa manera:

 compile com.google.android.gms:play-services-base:6.5.87 compile com.google.android.gms:play-services-maps:6.5.87 

Puede leer toda la lista de "partes" en este enlace

Aquí hay un guión que escribí para contar el número de métodos en cada jar (y en total) para una carpeta específica.

Una vez que se cuentan los métodos se puede concentrar en la refactorización y la eliminación de bibliotecas pesadas.

Es necesario habilitar el soporte Dex para eso. Así que necesitas hacer los siguientes pasos:

  1. Gradle plugin v0.14.0 para Android agrega soporte para multi-dex. Para habilitarlo, solo tienes que declararlo en build.gradle:
 android { defaultConfig { ... multiDexEnabled = true } } 
  1. Si el soporte de la aplicación> 5.0 (es decir, si su minSdkVersion es 20 o menos) también tiene que parche dinámico de la aplicación ClassLoader, por lo que será capaz de cargar clases de dexes secundarios. Para eso puede agregar esta lib.
  dependencies { ... compile 'com.android.support:multidex:1.0.0' } 
  1. Habilitar en código para que tenga esta opción. Elija uno que más le convenga

A. Agregar MultiDexApplication en manifiesto manifiesto

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.multidex.App"> <application android:name="android.support.multidex.MultiDexApplication"> </application> </manifest> 

B. Extender la aplicación mediante MultiDexApplication

 public class App extends MultiDexApplication { .. } 

C. instalarlo en la aplicación para adjuntar el contexto base.

 public class App { protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); .. } } 

Para obtener más información a través de este enlace MultiDex .

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.