How to shrink code - 65k method limit in dex

52,604

Solution 1

It looks like Google has finally implementing a workaround/fix for surpassing the 65K method limit of dex files.

About the 65K Reference Limit

Android application (APK) files contain executable bytecode files in the form of Dalvik Executable (DEX) files, which contain the compiled code used to run your app. The Dalvik Executable specification limits the total number of methods that can be referenced within a single DEX file to 65,536, including Android framework methods, library methods, and methods in your own code. Getting past this limit requires that you configure your app build process to generate more than one DEX file, known as a multidex configuration.

Multidex support prior to Android 5.0

Versions of the platform prior to Android 5.0 use the Dalvik runtime for executing app code. By default, Dalvik limits apps to a single classes.dex bytecode file per APK. In order to get around this limitation, you can use the multidex support library, which becomes part of the primary DEX file of your app and then manages access to the additional DEX files and the code they contain.

Multidex support for Android 5.0 and higher

Android 5.0 and higher uses a runtime called ART which natively supports loading multiple dex files from application APK files. ART performs pre-compilation at application install time which scans for classes(..N).dex files and compiles them into a single .oat file for execution by the Android device. For more information on the Android 5.0 runtime, see Introducing ART.

See: Building Apps with Over 65K Methods


Multidex Support Library

This library provides support for building apps with multiple Dalvik Executable (DEX) files. Apps that reference more than 65536 methods are required to use multidex configurations. For more information about using multidex, see Building Apps with Over 65K Methods.

This library is located in the /extras/android/support/multidex/ directory after you download the Android Support Libraries. The library does not contain user interface resources. To include it in your application project, follow the instructions for Adding libraries without resources.

The Gradle build script dependency identifier for this library is as follows:

com.android.support:multidex:1.0.+ This dependency notation specifies the release version 1.0.0 or higher.


You should still avoid hitting the 65K method limit by actively using proguard and reviewing your dependencies.

Solution 2

you can use the multidex support library for that, To enable multidex

1) include it in dependencies:

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

2) Enable it in your app:

defaultConfig {
    ...
    minSdkVersion 14
    targetSdkVersion 21
    ....
    multiDexEnabled true
}

3) if you have a application class for your app then Override the attachBaseContext method like this:

package ....;
...
import android.support.multidex.MultiDex;

public class MyApplication extends Application {
  ....
   @Override
   protected void attachBaseContext(Context context) {
    super.attachBaseContext(context);
    MultiDex.install(this);
   }
}

4) if you don't have a application class for your application then register android.support.multidex.MultiDexApplication as your application in your manifest file. like this:

<application
    ...
    android:name="android.support.multidex.MultiDexApplication">
    ...
</application>

and it should work fine!

Solution 3

Play Services 6.5+ helps: http://android-developers.blogspot.com/2014/12/google-play-services-and-dex-method.html

"Starting with version 6.5, of Google Play services, you’ll be able to pick from a number of individual APIs, and you can see"

...

"this will transitively include the ‘base’ libraries, which are used across all APIs."

This is good news, for a simple game for example you probably only need the base, games and maybe drive.

"The complete list of API names is below. More details can be found on the Android Developer site.:

  • com.google.android.gms:play-services-base:6.5.87
  • com.google.android.gms:play-services-ads:6.5.87
  • com.google.android.gms:play-services-appindexing:6.5.87
  • com.google.android.gms:play-services-maps:6.5.87
  • com.google.android.gms:play-services-location:6.5.87
  • com.google.android.gms:play-services-fitness:6.5.87
  • com.google.android.gms:play-services-panorama:6.5.87
  • com.google.android.gms:play-services-drive:6.5.87
  • com.google.android.gms:play-services-games:6.5.87
  • com.google.android.gms:play-services-wallet:6.5.87
  • com.google.android.gms:play-services-identity:6.5.87
  • com.google.android.gms:play-services-cast:6.5.87
  • com.google.android.gms:play-services-plus:6.5.87
  • com.google.android.gms:play-services-appstate:6.5.87
  • com.google.android.gms:play-services-wearable:6.5.87
  • com.google.android.gms:play-services-all-wear:6.5.87

Solution 4

In versions of Google Play services prior to 6.5, you had to compile the entire package of APIs into your app. In some cases, doing so made it more difficult to keep the number of methods in your app (including framework APIs, library methods, and your own code) under the 65,536 limit.

From version 6.5, you can instead selectively compile Google Play service APIs into your app. For example, to include only the Google Fit and Android Wear APIs, replace the following line in your build.gradle file:

compile 'com.google.android.gms:play-services:6.5.87'

with these lines:

compile 'com.google.android.gms:play-services-fitness:6.5.87'
compile 'com.google.android.gms:play-services-wearable:6.5.87'

for more reference, you can click here

Solution 5

You could use Jar Jar Links to shrink huge external libraries like Google Play Services (16K methods!)

In your case you will just rip everything from Google Play Services jar except common internal and drive sub-packages.

Share:
52,604
Jared Rummler
Author by

Jared Rummler

software engineer • android enthusiast • entrepreneur • father of two • husband • runner • cancer survivor • hacker • nerd

Updated on September 08, 2020

Comments

  • Jared Rummler
    Jared Rummler almost 4 years

    I have a rather large Android app that relies on many library projects. The Android compiler has a limitation of 65536 methods per .dex file and I am surpassing that number.

    There are basically two paths you can choose (at least that I know of) when you hit the method limit.

    1) Shrink your code

    2) Build multiple dex files (see this blog post)

    I looked into both and tried to find out what was causing my method count to go so high. The Google Drive API takes the biggest chunk with the Guava dependency at over 12,000. Total libs for Drive API v2 reach over 23,000!

    My question I guess is, what do you think I should do? Should I remove Google Drive integration as a feature of my app? Is there a way to shrink the API down (yes, I use proguard)? Should I go the multiple dex route (which looks rather painful, especially dealing with third party APIs)?

  • Ivan Morgillo
    Ivan Morgillo almost 10 years
    I'm looking for a proper way to do this with Gradle :-/ Any hint?
  • Pacerier
    Pacerier over 9 years
    +1, Why doesn't people upvote correct answers when they are answered by the same person?
  • ericn
    ericn over 9 years
    this looks promissing but I got Warning: butterknife.internal.ButterKnifeProcessor: can't find superclass or interface javax.annotation.processing.AbstractProcessor when running ./gradlew :myapp:proguardDevDebug
  • Brian White
    Brian White over 9 years
    Any information on how to do that within an Eclipse project?
  • Csaba Toth
    Csaba Toth over 9 years
    I'm not in a position to upgrade to that version yet. But if your project is Maven based, then hopefully you just have to solve that in you maven pom.
  • Csaba Toth
    Csaba Toth over 9 years
    @webo80 Well, this only helps if you are up to 6.5.87 version. I wonder about petey's answer, that proguard strips down unused functions. I wonder if that involves 2rd party libs too, or just your own stuff. I should read more about proguard.
  • Vihaan Verma
    Vihaan Verma about 9 years
    min api level becomes 14 !
  • milosmns
    milosmns about 9 years
    @BrianWhite The only solution for now seems to strip the .jar file with some external tool..
  • Brian White
    Brian White about 9 years
    I ended up using this tool: gist.github.com/dextorer/a32cad7819b7f272239b
  • Brian White
    Brian White about 9 years
    During development, though, proguard isn't generally run (at last not with Eclipse) so you can't benefit from the shrinkage until doing a release build.
  • hardik9850
    hardik9850 almost 9 years
    How to do it in eclipse ?
  • philipp
    philipp almost 9 years
    We wrote a small Gradle plugin to give you your current method count on each build. Was helpful to us to manage libraries - github.com/KeepSafe/dexcount-gradle-plugin
  • EZDsIt
    EZDsIt about 8 years
    @CsabaToth, You saved me! I added only a few of the list above instead of full 'com.google.android.gms:play-services', and that made the difference!