SJ cartoon avatar

Mobile Android Libraries - The Catch... 64k Method Limit

I ended my last post about Android Libraries talking about “The Catch” - and no, I’m not referring to any memorable sports moments. I’m talking about the pain-in-the-ass 64k method limit in Android apps that ALWAYS pops up at the wrong time.

In short, from Wire:

Code generated by Wire has many fewer methods than standard protocol buffer code, which helps applications avoid the notorious 64k limit on methods in Android applications.

When you exceed the 64k method limit in Android, you can’t compile anymore. Now, you might think that’s an impossible number for your lil ol’ app to get to, however, when you start pulling in dependencies, libraries, and the monster Google Play Services - that number creeps up much faster than you would expect (also… surprisingly… with Retrolambda lambdas).

Disclaimer: I’m going to present a few ways for figuring out roughly how many methods your at for your app, but this isn’t going to be exact. The question I try to answer is: “Am I near 64k or not? If so, why?”

Do It Yourself!

To figure out how many methods your libraries are using, you can run this handy little command over the .jar files which contain your dependencies.

for f in *.jar;
  do echo $f;
  [PATH_TO_SDK]/build-tools/23.0.1/dx --dex --output=$f.dex $f
  cat $f.dex | head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"' | xargs echo $f  >> temp
done

The natural question here is… Why would I want to re-download all those jars? Well, no need. When you do a build in Android Studio, all of the .jar files your app requires end up in: app/build/intermediates/pre-dexed/release - so just run the command from there.

Here is a sample of the output - as you can see, Commons, Jackson, Google Play, and Shinobi are the biggest contributors to the method count problem in this example.

android-saripaar-2.0-SNAPSHOT_5f124f5d7c9eccff82e98e9cc285cc20f79d3248.jar 697
butterknife-7.0.1_a676ab0c800771110bc76163fe6f166c26c5e05a.jar 342
com.android.support-support-v4-22.2.0_81faf53e0c24382eabb7924a77d0a2e37ee0574f.jar 7946
com.couchbase.lite-couchbase-lite-android-1.1.0_fb4a6bdfbe621685a7257828c23b52837bc74d3a.jar 149
com.crashlytics.sdk.android-answers-1.3.2_fd057db4fb66058975f05d3a59c44237528955bb.jar 366
com.crashlytics.sdk.android-beta-1.1.3_699a4a39577a9616572ce77029b31bae997c6236.jar 132
com.crashlytics.sdk.android-crashlytics-2.5.2_e26e4f6ec70d78b5711000da00e032cbc9e6b7b2.jar 75
com.crashlytics.sdk.android-crashlytics-core-2.3.5_768ebcc1a5af7f1a92fd4d232ca551ac9950c710.jar 930
com.google.android.gms-play-services-analytics-8.3.0_02b1bb159e9c2fc2a559f4e5653838705c37caf6.jar 3137
com.google.android.gms-play-services-base-8.3.0_4bdeee1b07e7ea5b0a754f3e39370037ef1b8bde.jar 641
com.google.android.gms-play-services-basement-8.3.0_138a251c1f8f7071457c2e1c937928c22570086b.jar 4410
com.google.android.gms-play-services-identity-8.3.0_f2136366514c700ec8665eedcc10a652fb195d01.jar 180
com.google.android.gms-play-services-location-8.3.0_7ea9b778ca9aaa4b1eeb28d262137a389c4cb20f.jar 1756
com.google.android.gms-play-services-maps-8.3.0_77120a7403ad7cef031794e3836e6fa459110fb6.jar 2520
commons-io-1.3.2_e966171d3afd671b51e947a69c8a1703f8565d89.jar 807
commons-lang3-3.3.2_1e1f64641ec01dee0387126ec2961b92812c8798.jar 3573
couchbase-lite-java-core-1.1.0_a2dab49d7731824baba29842ce3b0b37e845690a.jar 2822
go-android-shinobicharts-unspecified_4086f81292b3384566affa42a0389ec25aed7e33.jar 2
gson-2.3.1_e61ad7d237940559d56c1be31c4d872d755d79d5.jar 1231
internal_impl-22.2.0_890eb73389e5192ae5d735a5aafcd44f2e09dddc.jar 2686
io.fabric.sdk.android-fabric-1.3.6_af22989486b5129447bb5d2d88ba6c709acc4eb1.jar 1720
jackson-annotations-2.5.0_d5f8a661c5b76c6e961f22fd79a0bcc9598cc740.jar 191
jackson-core-2.5.0_b7217b5016c63620a8b3b25dc6a993c936fa61db.jar 1934
jackson-databind-2.5.0_5e9ecd28432f69c62bf673619ba40008270c1d29.jar 7729
joda-time-2.8.2-no-tzdb_b5e3e2d523d51712b5405a4809996451fb73784f.jar 4972
net.danlew-android.joda-2.8.2_ced9448869e5ae2564879e67dca64ee0c51e97a8.jar 158
okhttp-2.4.0_c503c2643db4533683d50a5599b6d249fafca601.jar 2044
okhttp-urlconnection-2.4.0_7555420810f6e4385757dc0a39e2e4e67c4874a1.jar 355
okio-1.4.0_5e3240200645ab08d811ba96b9206264cc5ee56a.jar 594
retrofit-1.9.0_15b043ce5ef28e3a635e1dbb75ca204fef5619ce.jar 766
robospice-1.4.14_fd2b2c443b89438e33c5c93ec0a763de4fd83619.jar 746
robospice-cache-1.4.14_97383415ee5f93898f9c9c2b7fcc6da57ce5f711.jar 383
robospice-okhttp-1.4.14_8820eaf48e1ce64ba9877958db5b07934075d19e.jar 71
robospice-retrofit-1.4.14_4047e4eabada043d3573672cc36a037af7bbec6f.jar 98
shinobicharts-android-premium-1.7.2-0_e6b7a2d66873f74f1d4959b5ef99bd072a3dc406.jar 4090
stateless4j-2.4.0_f28d610921143444c7c2db91ad83250953f2beed.jar 227
support-annotations-22.2.0_80c084da14c8dd9c2ced2b61eaace4f074c4f289.jar 20
timber-3.1.0_1da35319daca670963427af879c1a84103261084.jar 93

One APK At a Time

If the command line isn’t your thing, this handy little website will allow you to upload your APK and it will generate a breakdown for you.

Just drag your APK in and view the results.

APK Method Count

You can expand and collapse as you see fit!

One by One

This method isn’t very efficient, but if you’re evaluating a library for use and just need to get an idea of the impact, you can go to methodscount.com, type in the library as you would in a Gradle file and check out the results.

MethodCounts.com

Plug and Play

Just the other day on Twitter, I saw that the methodscount.com people had made an Android Studio plugin! Check it out here.

So now, all you do is put something in your Gradle, and wait while methodscount retrieves information from the server, hover over your library, and look at the method counts + dependencies!

Pretty freaking sweet, eh?

MethodCounts Gradle Plugin

What Do I Do?

Originally, I wanted this post to be about some ways to remedy this problem, but truthfully, a couple of months ago Matthias from SoundCloud posted these two articles - and frankly, he did a much better job than I would have done. So, I’ll simply link to his EXCELLENT articles on fixing Android’s method limit problems (part 1 and part 2). Read these… Like… Now.

The TLDR version is:

  • Remove Dependencies
  • Replace Dependencies
  • Proguard
  • Multi-Dex

Feature Photo credit: Joe Shlabotnik / Foter / CC BY-NC-SA