Brandon
Brandon

Reputation: 1886

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

I started a new app which uses firebase features heavily as well as the support libraries. I quickly hit the 65k dex limit, even though there is no reason I should be there given the simplicity of the app. I know I need to exclude certain dependencies that I have no use for, so I have been using gradlew app:dependencies to analyze the dependencies and pull out what is pulled in more than once or things I don't need.

Despite tons of excludes, I'm unable to get the method count down considerably (only 3%). Am I just stuck with multi-dex? If not, how do I effectively decrease method count more?

More information:

Here is the before/after of build.gradle depencies block and the gradlew app:dependencies output. I'm happy to post the dexcount text output of how many methods each library has if that will help. I can say that the biggest contributors to method count are the support libs and com.google.common.* and com.google.android.gms.*

Before Slimming

After Slimming

Before: build.gradle dependency block (no excludes)

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:multidex:1.0.2'
    implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
    implementation "com.android.support:recyclerview-v7:$supportLibraryVersion"
    implementation "com.android.support:design:$supportLibraryVersion"
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation "com.android.support:cardview-v7:$supportLibraryVersion"
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
    implementation('com.oakwoodsc.rxfirestore:rxfirestore-debug:1.0@aar') {
        exclude group: 'io.reactivex.rxjava2', module: 'rxandroid'
        exclude group: 'io.reactivex.rxjava2', module: 'rxjava'
    }
    implementation 'com.firebaseui:firebase-ui-auth:3.1.0' // Remove once custom version
    implementation "com.google.android.gms:play-services-location:$firebaseVersion"
    implementation "com.google.firebase:firebase-firestore:$firebaseVersion"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

Before: gradlew app:dependencies output

Lots of duplication!

+--- com.google.firebase:firebase-core:11.4.2
|    \--- com.google.firebase:firebase-analytics:11.4.2
|         +--- com.google.android.gms:play-services-basement:11.4.2
|         |    +--- com.android.support:support-v4:25.2.0 -> 26.1.0
|         |    |    +--- com.android.support:support-compat:26.1.0
|         |    |    |    +--- com.android.support:support-annotations:26.1.0
|         |    |    |    \--- android.arch.lifecycle:runtime:1.0.0
|         |    |    |         +--- android.arch.lifecycle:common:1.0.0
|         |    |    |         \--- android.arch.core:common:1.0.0
|         |    |    +--- com.android.support:support-media-compat:26.1.0
|         |    |    |    +--- com.android.support:support-annotations:26.1.0
|         |    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|         |    |    +--- com.android.support:support-core-utils:26.1.0
|         |    |    |    +--- com.android.support:support-annotations:26.1.0
|         |    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|         |    |    +--- com.android.support:support-core-ui:26.1.0
|         |    |    |    +--- com.android.support:support-annotations:26.1.0
|         |    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|         |    |    \--- com.android.support:support-fragment:26.1.0
|         |    |         +--- com.android.support:support-compat:26.1.0 (*)
|         |    |         +--- com.android.support:support-core-ui:26.1.0 (*)
|         |    |         \--- com.android.support:support-core-utils:26.1.0 (*)
|         |    \--- com.google.android.gms:play-services-basement-license:11.4.2
|         +--- com.google.firebase:firebase-common:11.4.2
|         |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|         |    +--- com.google.android.gms:play-services-tasks:11.4.2
|         |    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|         |    |    \--- com.google.android.gms:play-services-tasks-license:11.4.2
|         |    \--- com.google.firebase:firebase-common-license:11.4.2
|         +--- com.google.firebase:firebase-analytics-impl:11.4.2
|         |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|         |    +--- com.google.firebase:firebase-iid:11.4.2
|         |    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|         |    |    +--- com.google.firebase:firebase-common:11.4.2 (*)
|         |    |    \--- com.google.firebase:firebase-iid-license:11.4.2
|         |    +--- com.google.firebase:firebase-common:11.4.2 (*)
|         |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|         |    \--- com.google.firebase:firebase-analytics-impl-license:11.4.2
|         \--- com.google.firebase:firebase-analytics-license:11.4.2
+--- com.android.support:multidex:1.0.2
+--- com.android.support:appcompat-v7:26.1.0
|    +--- com.android.support:support-annotations:26.1.0
|    +--- com.android.support:support-v4:26.1.0 (*)
|    +--- com.android.support:support-vector-drawable:26.1.0
|    |    +--- com.android.support:support-annotations:26.1.0
|    |    \--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:animated-vector-drawable:26.1.0
|         +--- com.android.support:support-vector-drawable:26.1.0 (*)
|         \--- com.android.support:support-core-ui:26.1.0 (*)
+--- com.android.support:recyclerview-v7:26.1.0
|    +--- com.android.support:support-annotations:26.1.0
|    +--- com.android.support:support-compat:26.1.0 (*)
|    \--- com.android.support:support-core-ui:26.1.0 (*)
+--- com.android.support:design:26.1.0
|    +--- com.android.support:support-v4:26.1.0 (*)
|    +--- com.android.support:appcompat-v7:26.1.0 (*)
|    +--- com.android.support:recyclerview-v7:26.1.0 (*)
|    \--- com.android.support:transition:26.1.0
|         +--- com.android.support:support-annotations:26.1.0
|         \--- com.android.support:support-v4:26.1.0 (*)
+--- com.android.support.constraint:constraint-layout:1.0.2 -> 1.1.0-beta1
|    \--- com.android.support.constraint:constraint-layout-solver:1.1.0-beta1
+--- com.android.support:cardview-v7:26.1.0
|    \--- com.android.support:support-annotations:26.1.0
+--- io.reactivex.rxjava2:rxandroid:2.0.1
|    \--- io.reactivex.rxjava2:rxjava:2.0.1 -> 2.1.5
|         \--- org.reactivestreams:reactive-streams:1.0.1
+--- io.reactivex.rxjava2:rxjava:2.1.5 (*)
+--- com.oakwoodsc.rxfirestore:rxfirestore-debug:1.0
+--- com.firebaseui:firebase-ui-auth:3.1.0
|    +--- com.android.support:design:26.1.0 (*)
|    +--- com.android.support:customtabs:26.1.0
|    |    +--- com.android.support:support-compat:26.1.0 (*)
|    |    \--- com.android.support:support-annotations:26.1.0
|    +--- com.android.support.constraint:constraint-layout:1.1.0-beta1 (*)
|    +--- com.google.firebase:firebase-auth:11.4.2
|    |    +--- com.google.android.gms:play-services-base:11.4.2
|    |    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    |    |    \--- com.google.android.gms:play-services-base-license:11.4.2
|    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    +--- com.google.firebase:firebase-common:11.4.2 (*)
|    |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    |    \--- com.google.firebase:firebase-auth-license:11.4.2
|    +--- com.google.android.gms:play-services-auth:11.4.2
|    |    +--- com.google.android.gms:play-services-auth-api-phone:11.4.2
|    |    |    +--- com.google.android.gms:play-services-base:11.4.2 (*)
|    |    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    |    |    \--- com.google.android.gms:play-services-auth-api-phone-license:11.4.2
|    |    +--- com.google.android.gms:play-services-auth-base:11.4.2
|    |    |    +--- com.google.android.gms:play-services-base:11.4.2 (*)
|    |    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    |    |    \--- com.google.android.gms:play-services-auth-base-license:11.4.2
|    |    +--- com.google.android.gms:play-services-base:11.4.2 (*)
|    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    |    \--- com.google.android.gms:play-services-auth-license:11.4.2
|    \--- com.android.support:cardview-v7:26.1.0 (*)
+--- com.google.android.gms:play-services-location:11.4.2
|    +--- com.google.android.gms:play-services-base:11.4.2 (*)
|    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
|    \--- com.google.android.gms:play-services-location-license:11.4.2
\--- com.google.firebase:firebase-firestore:11.4.2
     +--- com.google.android.gms:play-services-basement:11.4.2 (*)
     +--- com.google.firebase:firebase-common:11.4.2 (*)
     +--- com.google.android.gms:play-services-tasks:11.4.2 (*)
     +--- com.squareup.okhttp:okhttp:2.7.2
     |    \--- com.squareup.okio:okio:1.6.0
     \--- com.google.guava:guava:20.0

After: build.gradle dependency block (with excludes all over)

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation("com.google.android.gms:play-services-base:$playServicesVersion") {
        exclude group: "com.android.support", module: "support-v4"
    }
    implementation 'com.android.support:multidex:1.0.2'
    implementation "com.android.support:design:$supportLibraryVersion"
    implementation("com.firebaseui:firebase-ui-auth:3.1.0") {  // Remove once custom version
        exclude group: "com.google.android.gms", module: "play-services-base"
        exclude group: "com.google.android.gms", module: "play-services-basement"
        exclude group: "com.google.android.gms", module: "play-services-tasks"
        exclude group: "com.android.support", module: "design"
        exclude group: "com.android.support", module: "support-compat"
        exclude group: "com.android.support", module: "support-annotations"
        exclude group: "com.android.support", module: "cardview-v7"
    }
    implementation("com.android.support:cardview-v7:$supportLibraryVersion") {
        exclude group: "com.android.support", module: "support-annotations"
    }
    implementation('com.oakwoodsc.rxfirestore:rxfirestore-debug:1.0@aar') {
        exclude group: 'io.reactivex.rxjava2', module: 'rxandroid'
        exclude group: 'io.reactivex.rxjava2', module: 'rxjava'
    }
    implementation("com.google.android.gms:play-services-location:$playServicesVersion") {
        exclude group: "com.google.android.gms", module: "play-services-base"
        exclude group: "com.google.android.gms", module: "play-services-tasks"
        exclude group: "com.google.android.gms", module: "play-services-basement"
    }
    implementation("com.google.firebase:firebase-firestore:$playServicesVersion") {
        exclude group: "com.google.android.gms", module: "play-services-basement"
        exclude group: "com.google.android.gms", module: "play-services-tasks"
    }
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

After: gradlew app:dependencies output:

Less duplication...

+--- com.google.android.gms:play-services-base:11.4.2
|    +--- com.google.android.gms:play-services-basement:11.4.2
|    |    \--- com.google.android.gms:play-services-basement-license:11.4.2
|    +--- com.google.android.gms:play-services-tasks:11.4.2
|    |    +--- com.google.android.gms:play-services-basement:11.4.2 (*)
|    |    \--- com.google.android.gms:play-services-tasks-license:11.4.2
|    \--- com.google.android.gms:play-services-base-license:11.4.2
+--- com.android.support:multidex:1.0.2
+--- com.android.support:design:26.1.0
|    +--- com.android.support:support-v4:26.1.0
|    |    +--- com.android.support:support-compat:26.1.0
|    |    |    +--- com.android.support:support-annotations:26.1.0
|    |    |    \--- android.arch.lifecycle:runtime:1.0.0
|    |    |         +--- android.arch.lifecycle:common:1.0.0
|    |    |         \--- android.arch.core:common:1.0.0
|    |    +--- com.android.support:support-media-compat:26.1.0
|    |    |    +--- com.android.support:support-annotations:26.1.0
|    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|    |    +--- com.android.support:support-core-utils:26.1.0
|    |    |    +--- com.android.support:support-annotations:26.1.0
|    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|    |    +--- com.android.support:support-core-ui:26.1.0
|    |    |    +--- com.android.support:support-annotations:26.1.0
|    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|    |    \--- com.android.support:support-fragment:26.1.0
|    |         +--- com.android.support:support-compat:26.1.0 (*)
|    |         +--- com.android.support:support-core-ui:26.1.0 (*)
|    |         \--- com.android.support:support-core-utils:26.1.0 (*)
|    +--- com.android.support:appcompat-v7:26.1.0
|    |    +--- com.android.support:support-annotations:26.1.0
|    |    +--- com.android.support:support-v4:26.1.0 (*)
|    |    +--- com.android.support:support-vector-drawable:26.1.0
|    |    |    +--- com.android.support:support-annotations:26.1.0
|    |    |    \--- com.android.support:support-compat:26.1.0 (*)
|    |    \--- com.android.support:animated-vector-drawable:26.1.0
|    |         +--- com.android.support:support-vector-drawable:26.1.0 (*)
|    |         \--- com.android.support:support-core-ui:26.1.0 (*)
|    +--- com.android.support:recyclerview-v7:26.1.0
|    |    +--- com.android.support:support-annotations:26.1.0
|    |    +--- com.android.support:support-compat:26.1.0 (*)
|    |    \--- com.android.support:support-core-ui:26.1.0 (*)
|    \--- com.android.support:transition:26.1.0
|         +--- com.android.support:support-annotations:26.1.0
|         \--- com.android.support:support-v4:26.1.0 (*)
+--- com.firebaseui:firebase-ui-auth:3.1.0
|    +--- com.android.support:customtabs:26.1.0
|    +--- com.android.support.constraint:constraint-layout:1.1.0-beta1
|    |    \--- com.android.support.constraint:constraint-layout-solver:1.1.0-beta1
|    +--- com.google.firebase:firebase-auth:11.4.2
|    |    +--- com.google.firebase:firebase-common:11.4.2
|    |    |    \--- com.google.firebase:firebase-common-license:11.4.2
|    |    \--- com.google.firebase:firebase-auth-license:11.4.2
|    \--- com.google.android.gms:play-services-auth:11.4.2
|         +--- com.google.android.gms:play-services-auth-api-phone:11.4.2
|         |    \--- com.google.android.gms:play-services-auth-api-phone-license:11.4.2
|         +--- com.google.android.gms:play-services-auth-base:11.4.2
|         |    \--- com.google.android.gms:play-services-auth-base-license:11.4.2
|         \--- com.google.android.gms:play-services-auth-license:11.4.2
+--- com.android.support:cardview-v7:26.1.0
+--- com.oakwoodsc.rxfirestore:rxfirestore-debug:1.0
+--- com.google.android.gms:play-services-location:11.4.2
|    \--- com.google.android.gms:play-services-location-license:11.4.2
+--- com.google.firebase:firebase-firestore:11.4.2
|    +--- com.google.firebase:firebase-common:11.4.2 (*)
|    +--- com.squareup.okhttp:okhttp:2.7.2
|    |    \--- com.squareup.okio:okio:1.6.0
|    \--- com.google.guava:guava:20.0
+--- io.reactivex.rxjava2:rxandroid:2.0.1
|    \--- io.reactivex.rxjava2:rxjava:2.0.1 -> 2.1.5
|         \--- org.reactivestreams:reactive-streams:1.0.1
\--- io.reactivex.rxjava2:rxjava:2.1.5 (*)

Upvotes: 1

Views: 1876

Answers (2)

Bryan Herbst
Bryan Herbst

Reputation: 67189

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.

Upvotes: 1

martinomburajr
martinomburajr

Reputation: 1265

Proguard is the key to your problems. Ensure that your app's build.gradle file has the following under buildtypes

buildTypes {
    //debug
    //staging
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

In my case my release build, minifies the code, shrinks resources, and most importantly uses proguard to reduce code bloat brought by other libraries. You can copy the code proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

Watch this awesome short video on the benefits of Proguard by David East.

Also if you haven't already check the Proguard documentation out

Upvotes: 1

Related Questions