máquina - Android: mi aplicación es demasiado grande y da "No se puede ejecutar dex: ID de método no en[0, 0xffff]: 65536"?
máquina virtual dalvik y art (8)
*** NUEVO **** Todas las otras respuestas están desactualizadas. Aquí está la nueva solución
Android 5.0 y superior
La compatibilidad con Multi-dex se incluye automáticamente. De los documentos:
Android 5.0 y versiones posteriores utilizan un tiempo de ejecución llamado ART que admite de forma nativa la carga de múltiples archivos dex desde 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 archivos de clases (.. N) .dex y los compila en un solo 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 Introducción a ART.
Debajo de Android 5.0
Simplemente agregue la herramienta de soporte multidex de Android a su compilación 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''
}
Intento integrar mi aplicación con Box, Dropbox y Google Drive. Los 3 de estos servicios requieren una serie de jarras de terceros. Además, mi aplicación ya requiere algunos tarros de terceros. Ahora, cuando intento ejecutar mi aplicación desde eclipse, aparece el siguiente error:
No se puede ejecutar dex: la ID del método no está en [0, 0xffff]: 65536 Falló la conversión a formato Dalvik: no se puede ejecutar dex: la ID del método no está en [0, 0xffff]: 65536
Parece que este error ocurre porque mi aplicación tiene demasiados métodos. Estoy bastante seguro de que la mayoría de estos métodos provienen de jarras de terceros, por lo que no es realista intentar resolver esto simplificando mi código. Encontré estas dos sugerencias en línea.
agregue
dex.force.jumbo=true
a project.properties (y use la versión de adt 21). Hice esto, pero todavía recibo el error.Use varios archivos dex como se explica aquí: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html . Esta parece ser la única opción, pero no entiendo cómo se aplica en mi caso. El problema es que servicios como Drive tienen demasiadas dependencias. ¿Esta solución no requeriría que modifique la fuente de la unidad para usar la inflexión cuando me refiera a sus dependencias? (Esto claramente no es una opción).
Utilice proguard para reducir el código / métodos no utilizados. La exportación de mi aplicación con Proguard funciona, y la integración del servicio de documentos funciona como se espera en un dispositivo> 4.0. Sin embargo, los errores de clase no se producen cuando se prueba en un dispositivo 2.3.
Por lo tanto, espero algunos consejos sobre este tema. ¿La opción 2 es una solución para mi caso? ¿Hay alguna otra solución que deba considerar?
Debe habilitar el soporte de Dex para eso. Entonces debes seguir estos pasos:
- El complemento Gradle v0.14.0 para Android agrega soporte para multi-dex. Para habilitarlo, solo tiene que declararlo en build.gradle:
android { defaultConfig { ... multiDexEnabled = true } }
- si el soporte de la aplicación> 5.0 (es decir, si su minSdkVersion es 20 o inferior) también tiene que parchear dinámicamente la aplicación ClassLoader, por lo que podrá cargar clases desde dexes secundarios. para eso puedes agregar esta lib.
dependencies { ... compile ''com.android.support:multidex:1.0.0'' }
- habilitar en el código para que tenga estas opciones. elija uno que se adapte mejor a usted
A. Agregue aplicación MultiDex 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. Extienda la aplicación mediante MultiDexApplication
public class App extends MultiDexApplication { .. }
C. instálelo en la aplicación al adjuntar el contexto base.
public class App {
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
..
}
}
Para más ir a través de este enlace MultiDex .
La VM Dalvik puede tener un máximo de 65536 métodos por archivo dex, debido a que el conjunto de instrucciones bytecode no tiene forma de referirse a números de método que requieren más de 16 bits (como lo señala @danfuzz en los comentarios).
Si bien es posible solucionar esto usando múltiples archivos dex, Facebook encontró otra solución que podrían implementar dentro de su aplicación para evitar el problema.
La mayoría de los problemas para alcanzar el límite del método de 65k están relacionados con el uso de los servicios de Google Play mastodonticos en sus aplicaciones. Recientemente, puede obtener más granularidad cuando lo usa.
Siguiendo esta guía , puede usar solo las partes que desee. Probablemente esto solucionará el problema, evitará algunos trucos de magia negra o usará multiDex. Por ejemplo, si solo quiere Google Maps en su aplicación (y no está usando anuncios, monedero, desgaste de google, análisis, etc.), usar 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
Puedes leer la lista completa de "partes" en este enlace
Me enfrenté a este problema recientemente. Después de buscar en la web para una implementación más detallada, me di cuenta de que no había mucho más allá de:
- Bien, pero un poco desactualizado ahora que Gradle está aquí: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html
- No hay muchos detalles, pero una vaga idea de cómo se podría hacer: https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920
Me di cuenta de que el problema no era necesariamente que hubiera demasiados métodos en mi código, sino que el problema estaba en la dex
completa de mi código y en otras bibliotecas. Por lo tanto, si pudiera compilar mi código contra las bibliotecas pero no incluirlas en las classes.dex
, y luego dex
las bibliotecas por separado, y luego ponerlo todo junto en tiempo de ejecución, debería funcionar. El único problema que queda por resolver es el cargador de clases, que Facebook mencionó de paso.
Entonces, con un poco de reflexión y algunos códigos de Groovy, creo que encontré una forma relativamente estable de empaquetar las bibliotecas y el código de la aplicación en archivos dex
separados.
También puede desarrollar uno o más de estos como un complemento para su aplicación principal, en forma de un APK por separado disponible para su descarga. Ese APK expondría algún componente que usaría la aplicación principal, ya que no conozco la naturaleza de su integración con estos servicios, no puedo hacer una recomendación más específica al respecto. Utilizaría su propio <permission>
personalizado de nivel de signature
para asegurar las comunicaciones entre las dos aplicaciones. Y, como beneficio adicional, si el uso de la biblioteca de terceros agrega requisitos para permisos adicionales, solo necesitaría esos permisos en el complemento de APK, manteniendo su APK principal más pequeño.
Vea vm / LinearAlloc.c y puede encontrar este código: (5MiB bajo 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'' está editando esta memoria usando un puntero C nativo. Problema de LinealAlloc de IMHO y este problema de identificación de método es cosa diferente.
Here hay un script que escribí para contar el número de métodos en cada jar (y en total) para una carpeta específica.
Una vez que cuente los métodos, puede concentrarse en refactorizar y eliminar bibliotecas pesadas.