Поиск…


Вступление

DEX означает исполняемые файлы байт-кода Android (APK) в виде файлов Dalvik Executable (DEX), которые содержат скомпилированный код, используемый для запуска вашего приложения.

Спецификация исполняемого файла Dalvik ограничивает общее количество методов, на которые можно ссылаться в одном файле DEX, до 65 536 (64 КБ), включая методы каркаса Android, библиотечные методы и методы в вашем собственном коде.

Чтобы преодолеть этот предел, необходимо настроить процесс сборки приложений для создания более одного файла DEX, известного как Multidex.

замечания

Что такое dex?

Dex - это имя формата файла и кодировки, с которой компилируется код Java Java. Ранние версии Android загружали и исполняли двоичные файлы dex непосредственно на виртуальной машине Dalvik. В более поздних версиях Android используется Android Runtime (ART), которая обрабатывает файлы dex как промежуточное представление и выполняет дальнейшие компиляции на нем до запуска приложения.

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

Эта проблема:

Формат файла dex кодирует ограничение на количество методов, на которые можно ссылаться в одном бинарном файле. Поскольку часть формата файла, в которой хранится количество ссылок, составляет два байта, максимальное число ссылок на методы - 0xFFFF или 65535. Если приложение содержит больше, чем это число ссылок на методы, оно не скомпилируется.

Что с этим делать:

Google предоставил возможность обойти эту проблему, называемую Multidex. Он имеет компоненты времени компиляции и времени выполнения. Как следует из его названия, во время компиляции он будет делить код между одним или несколькими файлами dex . Во время выполнения он научит стандартного ClassLoader как искать классы из этих файлов.

Этот подход хорошо работает на новых устройствах, но имеет некоторые существенные недостатки. Это может значительно увеличить время запуска приложений, а на старых устройствах может возникнуть отказ Application Not Responding .

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

Как избежать ограничения:

Прежде чем настраивать приложение, чтобы разрешить использование ссылок на 64K или более, вы должны предпринять шаги, чтобы уменьшить общее количество ссылок, вызванных вашим кодом приложения, включая методы, определенные вашим кодом приложения или включенными библиотеками. Следующие стратегии помогут вам избежать попадания лимита ссылки dex:

  • Просмотрите прямые и транзитивные зависимости вашего приложения. Убедитесь, что любая большая зависимость библиотеки, которую вы включаете в приложение, используется таким образом, чтобы перераспределить количество добавляемого кода в приложение. Общим анти-шаблоном является включение очень большой библиотеки, потому что несколько полезных методов были полезны. Сокращение зависимостей от кода приложения часто помогает избежать ограничения ссылки на dex.
  • Удалите неиспользуемый код с помощью ProGuard. Настройте параметры ProGuard для вашего приложения, чтобы запустить ProGuard, и убедитесь, что у вас есть сокращения для релизов. Включение усадки гарантирует, что вы не отправляете неиспользованный код с вашими APK.

Первый момент требует усердия и дисциплины со стороны разработчика. При включении сторонних библиотек следует учитывать размер библиотеки. Например, две популярные библиотеки JSON - это Джексон и Гсон. Функционально они довольно похожи, но Gson имеет тенденцию видеть большее использование в Android. Одна из причин заключается в том, что Джексон весит около 9000 методов, тогда как Gson составляет 1900 человек.

Существует несколько инструментов, помогающих разработчикам отслеживать размер их приложения:

  • dexcount-gradle-plugin сообщает количество ссылок на методы в вашем APK или AAR для каждой сборки
  • dex-method-counts - это средство командной строки, которое подсчитывает количество ссылок на методы в APK
  • www.methodscount.com - это веб-служба, которая будет рассчитывать ссылки на методы в любом APK, который вы загружаете.

Мультидекс с помощью MultiDexApplication напрямую

Используйте этот параметр, если вам не нужен подкласс Application .

Это самый простой вариант, но таким образом вы не можете предоставить свой собственный подкласс Application . Если необходим подкласс Application , вам придется перейти на один из других вариантов, чтобы сделать это.

Для этого параметра просто укажите полное имя класса android.support.multidex.MultiDexApplication для свойства android:name тега application в AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

Multidex, расширяя приложение

Используйте этот параметр, если для вашего проекта требуется подкласс Application .

Задайте этот подкласс Application используя свойство android:name в файле манифеста внутри тега application .

В подклассе Application добавьте переопределение метода attachBaseContext() , и в этом методе вызовите MultiDex.install() :

package com.example;

import android.app.Application;
import android.content.Context;

/**
 * Extended application that support multidex 
 */
public class MyApplication extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

Убедитесь, что подкласс Application указан в теге application вашего AndroidManifest.xml:

<application
    android:name="com.example.MyApplication"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name">
</application>

Включение Multidex

Чтобы включить конфигурацию multidex, вам необходимо:

  • изменить конфигурацию сборки Gradle
  • использовать MultiDexApplication или включить MultiDex в своем классе Application

Конфигурация гребенки

В app/build.gradle добавьте следующие части:

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 24
        ...

        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

Включить MultiDex в приложении

Затем выполните один из трех вариантов:

Когда эти настройки конфигурации добавляются в приложение, инструменты сборки Android строят первичный dex (classes.dex) и поддерживают (classes2.dex, classes3.dex) по мере необходимости.
Затем система сборки упаковывает их в файл APK для распространения.

Ссылки метода подсчета на каждом сборке (плагин Gradle Dexcount)

Плагин dexcount подсчитывает методы и количество ресурсов класса после успешной сборки.

Добавьте плагин в app/build.gradle :

apply plugin: 'com.android.application'

buildscript {
    repositories {
        mavenCentral() // or jcenter()
    }

    dependencies {
        classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
    }
}

Примените плагин в файле app/build.gradle :

apply plugin: 'com.getkeepsafe.dexcount'

Ищите выходные данные, сгенерированные плагином:

../app/build/outputs/dexcount

Особенно полезной является диаграмма .html в:

../app/build/outputs/dexcount/debugChart/index.html

Multidex путем расширения MultiDexApplication

Это очень похоже на использование подкласса Application и переопределение attachBaseContext() .

Однако, используя этот метод, вам не нужно переопределять attachBaseContext() поскольку это уже сделано в суперклассе MultiDexApplication .

Расширьте MultiDexApplication вместо Application :

package com.example;

import android.support.multidex.MultiDexApplication;
import android.content.Context;

/**
 * Extended MultiDexApplication 
 */
public class MyApplication extends MultiDexApplication {

     // No need to override attachBaseContext()

     //..........
}

Добавьте этот класс в свой AndroidManifest.xml точно так же, как если бы вы расширяли приложение:

<application
    android:name="com.example.MyApplication"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name">
</application>


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow