Android: mi aplicación es demasiado grande y da “No se puede ejecutar dex: ID de método no en [0, 0xffff]: 65536”?

10 minutos de lectura

avatar de usuario
ab11

Estoy tratando de integrar mi aplicación con Box, Dropbox y Google Drive. Los 3 de estos servicios requieren una cantidad de frascos de terceros. Además, mi aplicación ya requiere algunos frascos de terceros. Ahora, cuando intento ejecutar mi aplicación desde Eclipse, aparece el siguiente error:

No se puede ejecutar dex: el ID del método no está en [0, 0xffff]: 65536 La conversión al formato Dalvik falló: no se puede ejecutar dex: el 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 parte de estos métodos provienen de frascos de terceros, por lo que no es realista tratar de resolver esto simplificando mi código. Encontré estas dos sugerencias en línea.

  1. agregar dex.force.jumbo=truea project.properties (y use adt versión 21). Hice esto pero sigo recibiendo el error.

  2. Use múltiples archivos dex como se explica aquí: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html. Parece probable que esta sea 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 Drive para usar la inflexión cuando me refiero a sus dependencias? (esto claramente no es una opción).

  3. Utilice proguard para reducir la eliminación de 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 esperaba en un dispositivo >4.0. Sin embargo, se lanzan errores classnotfound cuando se prueba en un dispositivo 2.3.

Por lo tanto, espero algún consejo sobre este tema. ¿Es la opción 2 una solución para mi caso? ¿Hay otra solución que deba considerar?

  • “Los 3 de estos servicios requieren una cantidad de frascos de terceros” — AFAIK, ninguno de ellos requiere ninguna JAR de terceros. Tu tienes elegido para utilizar JAR, y por lo tanto sus JAR dependientes, para acceder a esos servicios. Sin embargo, dado que se puede acceder a todos esos servicios por medios distintos a los clientes basados ​​en Java, todos tienen alguna API de servicio web subyacente. Por ejemplo, en el caso de Dropbox, es una API estilo REST: dropbox.com/developers/core/api

    – CommonsWare

    19 de marzo de 2013 a las 19:19

  • ¿Sería más exacto decir que las “bibliotecas de Android” para estos servicios requieren una cantidad de frascos de terceros?

    – ab11

    19 de marzo de 2013 a las 19:29

  • Mi punto es que no necesita usar esas bibliotecas. Los desarrolladores de Python no usan esos JAR. Los desarrolladores de Ruby no usan esos JAR. Los desarrolladores de JavaScript no usan esos JAR. Esos archivos JAR están allí para su comodidad, pero si le causan molestias, desplácese hacia abajo y acceda a su API de servicio web de manera más directa.

    – CommonsWare

    19/03/2013 a las 19:40

  • Yo diría que proguard es tu mejor apuesta. Pasaría algún tiempo investigando por qué está obteniendo excepciones ClassNotFound. Probablemente necesite modificar la configuración de proguard.

    – Jesús Freke

    19 de marzo de 2013 a las 22:38

  • Está cerca de la parte superior, debería verse como method_ids_size : 36700. dexdump es parte del SDK.

    – desvanecerse

    21 de marzo de 2013 a las 21:27

También puede desarrollar uno o más de estos como un complemento para su aplicación principal, en forma de un APK separado disponible para descargar. Ese APK expondría algún componente que usaría la aplicación principal; dado que no conozco la naturaleza de su integración con estos servicios, no puedo hacer una recomendación más específica al respecto. Usarías el tuyo signature-nivel personalizado <permission> 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á esos permisos en el APK del complemento, manteniendo su APK principal más pequeño.

  • esta es la solución más realista que he visto hasta ahora. Dejaré la pregunta sin responder por un momento, con la esperanza de obtener más comentarios, pero probablemente terminaré usando esto.

    – ab11

    19 de marzo de 2013 a las 20:13

  • No puedo encontrar un ejemplo de esta arquitectura de complemento. Me gustaría encontrar ejemplos que muestren cómo verificar si el complemento está instalado y cómo usar permisos personalizados para comunicaciones seguras. ¿Podría señalarme en la dirección correcta?

    – ab11

    19 de marzo de 2013 a las 21:46


  • @ab11: Bueno, dado que la naturaleza de la arquitectura de un complemento depende en gran medida de lo que realmente están haciendo los complementos, le resultará difícil encontrar ejemplos de propósito general. Aquí hay un ejemplo de un par de proyectos que implementan una interfaz de usuario de complemento mediante el paso RemoteViews del complemento al host: github.com/commonsguy/cw-omnibus/tree/master/RemoteViews DashClock de Roman Nurik muestra un widget de aplicación/widget de pantalla de bloqueo que admite complementos: code.google.com/p/dashclock

    – CommonsWare

    19 de marzo de 2013 a las 21:49

avatar de usuario
jason

*** NUEVO **** Todas las otras respuestas ahora están desactualizadas. Aquí está la nueva solución

Android 5.0 y superior

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

Android 5.0 y superior utiliza un tiempo de ejecución llamado ART que admite de forma nativa la carga de varios archivos dex desde los archivos APK de la aplicación. ART realiza una precompilación en el momento de la instalación de la aplicación, que busca archivos class(..N).dex y los compila en un solo archivo .oat para que lo ejecute el dispositivo Android. Para obtener más información sobre el tiempo de ejecución de Android 5.0, consulte Introducción a ART.

Por debajo de Android 5.0

Simplemente agregue la herramienta de soporte mul-dex de Android a su compilació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'
}

avatar de usuario
Raghav Sood

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

Si bien es posible arreglar esto usando múltiples archivos dex, Facebook Encontré otra solución que podrían implementar dentro de su aplicación para solucionar el problema.

  • después de muchas lecturas, todavía no tengo claro cómo puedo implementar su solución. ¿Agrego algo a mi aplicación para cambiar un búfer dalvik interno?

    – ab11

    19 de marzo de 2013 a las 19:32

  • @ab11 Debe crear una extensión nativa usando android-ndk, lo que aumenta el tamaño del búfer nativo.

    – Raghav Sood

    19 de marzo de 2013 a las 19:32

  • ¿Alguna posibilidad de que haya un ejemplo en línea de cómo hacer esto? Además, en general, ¿piensas que esta es una opción realista para un desarrollador (yo) que no tiene muy clara la solución?

    – ab11

    19 de marzo de 2013 a las 19:36

  • Nota: La restricción no es un “problema de asignación de memoria”. Es que el conjunto de instrucciones de código de bytes no tiene una forma de referirse a los números de método que requieren más de 16 bits. Tenía una solución para ese problema en progreso cuando dejé el equipo de Android, y parece que nadie lo solucionó mientras tanto (por desgracia).

    – danfuzz

    19 de marzo de 2013 a las 20:14

  • el problema de facebook era un problema de asignación de memoria y no es lo mismo que el problema de referencia del método de 16 bits. Tenga en cuenta, en particular, que su solución solo era necesaria para versiones anteriores de Android (froyo / gingerbread) y no hace nada en Honeycomb y posteriores. El límite de 16 bits se aplica por igual a todas las versiones pasadas y presentes.

    – desvanecerse

    21 de marzo de 2013 a las 21:26

Ver 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 el puntero C nativo. En mi humilde opinión, el problema de LinearAlloc y este problema de ID de método es algo diferente.

Me enfrenté a este problema recientemente. Después de buscar en la web 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 hubiera demasiados métodos en mi código, sino que todo el dex de mi código y otras bibliotecas fue el problema. Entonces, si pudiera compilar mi código contra las bibliotecas pero no incluirlas en el classes.dexy 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 abordar es el cargador de clases, que Facebook mencionó de pasada.

Entonces, con un poco de reflexión y un poco de código Groovy, creo que se me ocurrió una forma relativamente estable de empaquetar las bibliotecas y el código de la aplicación por separado. dex archivos

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

  • Veré eso, pero solo quería informarte de mi terrible solución. Tengo algunas bibliotecas externas que solo uso para ciertas cosas; en desarrollo, no necesito incluirlos en mi aplicación a menos que esté trabajando en esas funcionalidades específicas. entonces, los elimino de la carpeta libs para que no estén integrados en la aplicación y los coloco en la ruta de clases para que mi código se compile; obviamente, mi aplicación fallará si se usan esas características, pero volveré a poner la necesaria para desarrollarla. Cuando construyo para el lanzamiento, incluyo las bibliotecas porque progruard elimina las clases no utilizadas de las bibliotecas.

    – ab11

    25/10/2013 a las 14:52


avatar de usuario
webo80

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 de mastodoncia en sus aplicaciones. Recientemente, puede obtener más granularidad al usarlo.

Siguiente esta guía, puede usar solo las partes que desee. Probablemente esto solucione el problema, evitando algunos trucos de magia negra o usando multiDex. Por ejemplo, si solo quiere Google Maps en su aplicación (y no está usando anuncios, billetera, Google Wear, 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

Puede leer la lista completa de “partes” en este enlace

  • Veré eso, pero solo quería informarte de mi terrible solución. Tengo algunas bibliotecas externas que solo uso para ciertas cosas; en desarrollo, no necesito incluirlos en mi aplicación a menos que esté trabajando en esas funcionalidades específicas. entonces, los elimino de la carpeta libs para que no estén integrados en la aplicación y los coloco en la ruta de clases para que mi código se compile; obviamente, mi aplicación fallará si se usan esas características, pero volveré a poner la necesaria para desarrollarla. Cuando construyo para el lanzamiento, incluyo las bibliotecas porque progruard elimina las clases no utilizadas de las bibliotecas.

    – ab11

    25/10/2013 a las 14:52


avatar de usuario
tom susel

Aquí es un script que escribí para contar la cantidad de métodos en cada contenedor (y en total) para una carpeta específica.

Una vez que cuente los métodos, puede concentrarse en refactorizar y eliminar bibliotecas pesadas.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad