Mobile Development 20 min read

How to Fix INSTALL_FAILED_DEXOPT on Android <3.0 with Custom Dex Splitting

This article explains why INSTALL_FAILED_DEXOPT occurs on Android versions below 3.0, details Google’s official multidex solution, and presents a custom automatic dex‑splitting and dynamic loading approach that overcomes method‑count and LinearAlloc limits while maintaining app performance.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
How to Fix INSTALL_FAILED_DEXOPT on Android <3.0 with Custom Dex Splitting

Background

Shortly before a gray‑scale test, the project encountered INSTALL_FAILED_DEXOPT on Android devices below 3.0, causing installation failure. The root causes are the 65K method limit per DEX file and the LinearAlloc buffer limit used by DexOpt during installation.

Early Android versions used DexOpt to generate an optimized ODEX file, but DexOpt stored method IDs in a short‑sized linked list (max 65,536 methods) and relied on a fixed‑size LinearAlloc buffer (5 MB‑16 MB depending on the OS version). When these limits are exceeded, DexOpt crashes.

Although newer Android releases lifted the 65K limit and expanded LinearAlloc, compatibility with older devices still requires a workaround. The project therefore adopted a dex‑splitting strategy to keep the primary DEX and LinearAlloc usage within limits.

Google Official Solution

1. Dex Splitting

Google introduced multidex support in Android Build Tools 21.1. The Gradle configuration is:

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 21
        multiDexEnabled true
    }
}

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

When using Ant, the Gradle settings must be translated to dx command‑line options. The key dx parameters are:

--multi-dex: enable multiple DEX files.

--main-dex-list=<file>: specify classes that must reside in the primary DEX.

--minimal-main-dex: include only the listed classes in the primary DEX.

By adding the hidden --set-max-idx-number parameter (e.g., 48000), the build produced a second DEX file.

During this process, Android SDK Tools added a "v4" suffix to density‑specific resource directories to ensure compatibility with API level 4 and above.

2. Dex Loading

Google’s android-support-multidex.jar loads secondary DEX files at runtime. It can be activated in three ways:

Declare android.support.multidex.MultiDexApplication in the manifest.

Extend MultiDexApplication with a custom Application class.

Call MultiDex.install(this) from attachBaseContext() or onCreate() of an existing Application subclass.

This approach works but forces all secondary DEX files to reside at the APK root and loads them synchronously at startup.

Custom Automatic Dex Splitting and Dynamic Loading

1. Dex Splitting

The custom solution automates three steps:

Generate main-dex-list by scanning the project before obfuscation.

After ProGuard obfuscation, map the original class names to the obfuscated ones using the mapping file.

Split compiled classes into primary and secondary groups, then invoke dx to produce separate DEX files, placing secondary DEX files (or JARs) in the assets directory.

Android SDK’s mainDexClasses script is leveraged to produce the initial list, while ProGuard’s shrink step retains entry‑point classes.

2. Dex Loading

Instead of the official jar, a custom loader uses DexClassLoader to load secondary DEX files from assets. The loader reflects into the host PathClassLoader to merge its DexPathList.Element array with that of the DexClassLoader, effectively injecting the secondary classes into the main class‑loading path.

Loading can be performed synchronously at startup (e.g., in attachBaseContext()) or on demand for specific features.

3. Installation and Runtime

After packaging, the APK installs successfully on Android 4.3 devices and runs without crashes on Android 2.3 after the custom loader is invoked.

Performance Impact

Synchronously loading secondary DEX files adds overhead to the first launch after installation because the system must run DexOpt on each secondary DEX. Measurements show approximately 1200 ms on a GT‑I8160 (Android 2.3) and 1000 ms on a N‑i9250 (Android 4.3). Subsequent launches are fast (≈10 ms and 4 ms respectively). The size of each secondary DEX directly influences this cost.

Future Work

Further startup‑time optimizations such as splash screens and pre‑DexOpt.

Improving the build‑script performance (from >7 minutes to <10 seconds after two optimizations).

Exploring asynchronous or on‑demand loading of secondary DEX files.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidGradleDEXMultidexAntDexSplitting
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.