How to Shrink Code - 65K Method Limit in Dex

How to shrink code - 65k method limit in dex

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.

How to properly reduce an app method count (below dex-limit)

First things first, you don't need all those excludes. If two dependencies use com.android.support:support-v4:26.1.0, it is only included once. It is listed twice so you can see who depends on it.

One option you may want to consider is turning on ProGuard. This will strip out any unused code, including library code. In your case, it will likely get you under the 65k limit.

To use it, set this in your build.gradle:
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}

You will want to create proguard-rules.pro and populate it with some directive specific to your app. Be sure to check out the full documentation to see what you might need to include there.

While it is possible to stay under the 65k limit without ProGuard, most apps of moderate complexity will surpass it fairly quickly, and I've found that avoiding libraries such as AppCompat in an effort to stay under the 65k limit is generally more work than it is worth.

Even with ProGuard, some apps will encounter the 65k limit. Other apps may not want to use ProGuard for one reason or another. In these cases, your best option is to enable multidex, which allows you to go over the 65k limit.

Is there a way to limit method amount in main dex file while using MultiDex feature in Android Studio

dx tool has the following options:

  • --minimal-main-dex - will put only classes that selected by main-dex-list into the main dex.
  • --set-max-idx-number - undocumented option that determines maximum number of methods per single dex file.

You have to customize your build.gradle script by specifying those two options. In example (source):

tasks.withType(com.android.build.gradle.tasks.Dex) {    dexTask ->
def command = [] as List
command << ' --minimal-main-dex'
command << ' --set-max-idx-number=50000'
dexTask.setAdditionalParameters(command)
}

Note that this won't help if your main dex is too large. There're rules that govern which classes should be placed in main dex. I blogged about them here.

Edit (1-9-2016):
Version 1.5 of Android plugin doesn't allow to add additional parameters to dx, but it seems that it will be fixed in one of the upcoming versions.

Dex method count limit in older android versions

On 2.x there is a 5MB dexopt buffer limit. You are probably hitting that and not the "number of methods" limit. See Running apps containing large amount of code

The number of method references in a .dex file cannot exceed 64k API 17

You have too many methods. There can only be 65536 methods for dex.

As suggested you can use the multidex support.

Just add these lines in the module/build.gradle:

android {

defaultConfig {
...

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

dependencies {
implementation 'androidx.multidex:multidex:2.0.1' //with androidx libraries
//implementation 'com.android.support:multidex:1.0.3' //with support libraries

}

Also in your Manifest add the MultiDexApplication class from the multidex support library to the application element

    <?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="androidx.multidex.MultiDexApplication">

<!-- If you are using support libraries use android:name="android.support.multidex.MultiDexApplication" -->

<!--If you are using your own custom Application class then extend -->
<!--MultiDexApplication and change above line as-->
<!--android:name=".YourCustomApplicationClass"> -->

...
</application>
</manifest>

If you are using your own Application class, change the parent class from Application to MultiDexApplication.

If you can't do it, in your Application class override the attachBaseContext method with:

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

Another solution is to try to remove unused code with ProGuard - Configure the ProGuard settings for your app to run ProGuard and ensure you have shrinking enabled for release builds.



Related Topics



Leave a reply



Submit