10

I have multiple library projects and they all have dependency to Support Library. My application has dependency to these multiple library projects. Every library project contains references to support library's resources in their R.java file. This inflates the field ID count because of redundancy.

My app gets

DexIndexOverflowException: field ID not in [0, 0xffff]: 65536

because of this redundant R.java references.

Because of this my app has 47k methods while 65k field ids.

Edit:

I won't use multi-dex, it is not a solution to my problem. I want to shave redundant field IDs.

The question is not about how to work around the problem, the question is about how to get rid of the redundant field IDs. Using multi-dex won't remove the redundant field IDs.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Tony
  • 1,603
  • 3
  • 21
  • 40

3 Answers3

3

DexIndexOverflowException: field ID not in [0, 0xffff]: 65536

  • Android has pre-defined upper limit of Methods of 65536.

When?

The size of the DEX file’s method index is 16 bit, so it means that 65536 represents the total number of references that can be invoked by the code within a single DEX file. If overcome then arise this error.

Once you begin to include enough libraries that causes the 64K method limit to be reached, you need to remove extraneous dependencies.

How? Without using multiDex

ProGuard optimizes the bytecode, removes unused code instructions, and obfuscates the remaining classes, fields, and methods with short names.Resource shrinking is available with the Android plugin for Gradle, which removes unused resources from your packaged app, including unused resources in code libraries. It works in conjunction with code shrinking such that once unused code has been removed, any resources no longer referenced can be safely removed as well .

How to Enable Proguard

add minifyEnabled true to the appropriate build type in your build.gradle file.

android {
    buildTypes {
        release { //You can add this in debug mode
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }

}

NOTE

  1. The getDefaultProguardFile('proguard-android.txt') method gets the default ProGuard settings from the Android SDK tools->proguard->folder .

  2. The proguard-rules.pro file is where you can add custom ProGuard rules .

Resource shrinking

Resource shrinking works only in conjunction with code shrinking. After the code shrinker removes all unused code, the resource shrinker can identify which resources the app still uses.

buildTypes {
    release {
              minifyEnabled true
              shrinkResources true  //You can add this in debug mode
    }
}
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
  • `com.android.support:multidex:1.0.1` is needed for api 19 and lower only. Actually never worked for me, I was not succesful with multidex on api 19. I ended with Proguard shrink rules for release builds (then it works without multidex) – user1209216 Oct 20 '17 at 09:29
  • 1
    @user1209216 It never works by adding multidex in my case, but I can make it works by doing a little tweak. Though this answer doesn't help the op. – ישו אוהב אותך Oct 20 '17 at 09:35
  • 3
    **Don't keep whole packages!** Support library applies its own minimalistic proguard rules, which are more optimized than your suggestion. – Eugen Pechanec Oct 20 '17 at 14:22
3

Like @intellij-amiya's answer, using multidex or proguard will solve your problem and I personally recommend that.

If you do not want to follow that method, you can manually exclude duplicated dependencies.

Execute the following command in your terminal to find duplicated dependencies.

./gradlew :app:dependencies --configuration compile

or if you on windows,

gradlew.bat :app:dependencies --configuration compile

change :app as your project name.

Let's assume your gradle dependencies are like this:

compile 'com.android.support:support-compat:26.+'
compile 'com.android.support:support-fragment:26.+'

You will get output like below:

+--- com.android.support:support-compat:26.+ -> 26.0.0-alpha1
|    \--- com.android.support:support-annotations:26.0.0-alpha1
\--- com.android.support:support-fragment:26.+ -> 26.0.0-alpha1
     +--- com.android.support:support-compat:26.0.0-alpha1 (*)
     +--- com.android.support:support-core-ui:26.0.0-alpha1
     |    +--- com.android.support:support-annotations:26.0.0-alpha1
     |    \--- com.android.support:support-compat:26.0.0-alpha1 (*)
     \--- com.android.support:support-core-utils:26.0.0-alpha1
          +--- com.android.support:support-annotations:26.0.0-alpha1
          \--- com.android.support:support-compat:26.0.0-alpha1 (*)

And you can see dependencies marked with (*), and these dependencies can be excluded. You can see support-compat is duplicated, and exclude it is done by edit like this:

compile ('com.android.support:support-fragment:26.+') {
    exclude module: 'support-compat'
}

Repeating this until you can get the count below 64k

And now the hardest part remains.

In my experience, excluding some dependencies may cause build fail, runtime exceptions, and etc. So you need to check your application working well without problem.

Hope this help.

changhwan
  • 1,000
  • 8
  • 22
  • 1
    Dependencies marked with `(*)` only means they have been mentioned before. Don't exclude them. They are needed and only included once. – Eugen Pechanec Oct 20 '17 at 14:20
-1

My problem solved by adding "multiDexEnabled true" as following in Module build.gradle.

android {
          ...
          defaultConfig {
                          ...
                          multiDexEnabled true
                         }
         }
sunil
  • 796
  • 1
  • 8
  • 28