Android: мое приложение слишком велико и дает «Невозможно выполнить dex: идентификатор метода не в : 65536»?

Я пытаюсь интегрировать свое приложение с Box, Dropbox и Google Диском. Все 3 из этих услуг требуют нескольких сторонних банках. Кроме того, в моем приложении уже требуются несколько сторонних баннеров. Теперь, когда я пытаюсь запустить приложение из eclipse, я получаю следующую ошибку:

Не удалось выполнить идентификатор метода dex: не в [0, 0xffff]: 65536 Не удалось преобразовать формат Dalvik: невозможно выполнить идентификатор метода dex: не в [0, 0xffff]: 65536

Похоже, эта ошибка возникает из-за того, что в моем приложении слишком много методов. Я довольно уверен, что основная часть этих методов принадлежит сторонним банкам, поэтому нереально попытаться решить эту проблему, упростив мой код. Я нашел эти два предложения в Интернете.

  1. Добавьте dex.force.jumbo=true в project.properties (и используйте adt version 21). Я сделал это, но все еще получаю ошибку.

  2. Используйте несколько файлов dex, как описано здесь: http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html . Вероятно, это единственный вариант, но я не понимаю, как это применимо в моем случае. Проблема в том, что такие сервисы, как Drive, имеют слишком много зависимостей. Не будет ли это решение требовать, чтобы я изменил источник Drive, чтобы использовать перегиб при обращении к его зависимостям? (это явно не вариант).

  3. Использовать proguard для сжатия удалить неиспользуемый код / ​​методы. Экспорт моего приложения с помощью proguard действительно работает, и интеграция служб документов работает как ожидается на устройстве> 4.0. Однако при тестировании на устройстве 2.3 бросаются вызовы classnotfound.

Поэтому я надеюсь на некоторые советы по этому вопросу. Является ли вариант 2 решением для моего дела? Есть ли еще одно решение, которое я должен рассмотреть?

Вы также можете разработать один или несколько из них в качестве плагина для вашего основного приложения в виде отдельного APK, доступного для загрузки. То, что APK предоставит какой-то компонент, который будет использовать основное приложение, – поскольку я не знаю характера вашей интеграции с этими службами, я не могу сделать более конкретные рекомендации по этому поводу. Для обеспечения безопасности между двумя приложениями вы должны использовать свой собственный пользовательский уровень signature . И в качестве бонуса, если использование сторонней библиотеки добавляет требования к дополнительным разрешениям, вам понадобятся только эти разрешения в APK плагина, чтобы ваш основной APK был меньше.

*** NEW **** Все остальные ответы теперь устарели. Вот новое исправление

Android 5.0 и выше

Поддержка Multi-Dex включена автоматически. Из документов:

Android 5.0 и выше использует среду выполнения, называемую ART, которая поддерживает загрузку нескольких файлов dex из файлов APK приложения. ART выполняет предварительную компиляцию во время установки приложения, которая сканирует файлы classов (..N) .dex и компилирует их в один файл .oat для исполнения устройством Android. Дополнительные сведения о времени выполнения Android 5.0 см. В разделе Введение в ART.

Ниже Android 5.0

Просто добавьте инструмент поддержки мультиизынга Android к своей конструкции 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' } 

У Dalvik VM может быть максимум 65536 методов на файл dex из-за того, что набор команд байт-кода не имеет способа ссылаться на номера методов, требующие более 16 бит (как указано в комментариях @danfuzz).

Хотя это можно исправить с помощью нескольких файлов dex, Facebook нашел другое исправление, которое они могли бы развернуть в своем приложении, чтобы обойти эту проблему.

См. Vm / LinearAlloc.c, и вы можете найти этот код: (5MiB под Android 2.3.3, 8MiB после Android 4.0 в качестве моего расследования)

#define DEFAULT_MAX_LENGTH (5 * 1024 * 1024)

LinearAllocHdr * pHdr;

pHdr-> mapLength = DEFAULT_MAX_LENGTH;

Я полагаю, что «исправление в Facebook» редактирует эту память с помощью встроенного указателя C. Проблема IMHO LinearAlloc и эта проблема с идентификатором метода – это другое дело.

Недавно я столкнулся с этой проблемой. После прочесывания сети для более детальной реализации, я понял, что там было не так много, кроме:

Я понял, что проблема не обязательно в том, что в моем коде было слишком много методов, но проблема в том, что это был полный код моего кода и других библиотек. Поэтому, если бы я мог скомпилировать свой код с библиотеками, но не включать их в classes.dex , а затем dex библиотеки отдельно, а затем собрать все вместе во время выполнения, он должен работать. Единственная проблема, которую нужно решить, – это загрузчик classов, о котором Facebook упоминал попутно.

Итак, с небольшим reflectionм и некоторым кодом Groovy, я думаю, что придумал относительно стабильный способ упаковки библиотек и кода приложения в отдельные файлы dex .

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

Большинство проблем с ограничением метода 65k связаны с использованием мастодонтических сервисов Google Play в ваших приложениях. В последнее время вы можете получить дополнительную детализацию при ее использовании.

Следуя этому руководству , вы можете использовать только те части, которые вы хотите. Вероятно, это устранит проблему, избегая некоторых трюков с черной магией или используя multiDex. Например, если вы только хотите использовать Карты Google в своем приложении (и вы не используете рекламу, кошелек, одежду, аналитику и т. Д.), Использование всей зависимости – пустая трата времени / пространства. Вы можете использовать его так:

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

Вы можете прочитать весь список «частей» в этой ссылке

Вот сценарий, который я написал для подсчета количества методов в каждой банке (и в целом) для конкретной папки.

После того, как вы посчитаете методы, вы можете сосредоточиться на рефакторинге и удалении тяжелых библиотек.

Вам нужно включить поддержку Dex для этого. Поэтому вам нужно сделать следующие шаги:

  1. Gradle plugin v0.14.0 для Android добавляет поддержку multi-dex. Чтобы включить, просто нужно объявить его в файле build.gradle:
 android { defaultConfig { ... multiDexEnabled = true } } 
  1. если приложение поддерживает> 5.0 (то есть, если ваша minSdkVersion составляет 20 или ниже), вам также необходимо динамически исправлять приложение ClassLoader, чтобы он мог загружать classы из вторичных дексов. для этого вы можете добавить эту lib.
  dependencies { ... compile 'com.android.support:multidex:1.0.0' } 
  1. включите в код для этого параметра. выберите тот, который вам подходит лучше всего

A. Добавить MultiDexApplication в манифесте манифеста

     

B. Расширьте приложение MultiDexApplication

 public class App extends MultiDexApplication { .. } 

C. установите его в приложении в привязке базового контекста.

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

Для получения дополнительной информации перейдите по этой ссылке MultiDex .

Давайте будем гением компьютера.