Too Many Methods: How to Avoid Compile Errors on Submission

Mike Hines
Amazon Developers

--

By Mike Hines (@MikeFHines, http://developer.amazon.com)

As the size of mobile apps get larger, and services and tools get more complex, they add more method references to our apps. Google Play Services alone adds 29,460 methods (reference). The result is that we are hitting the original design limitations of Android build architecture. Specifically, we hit the inability of a single Dalvik Executable file (dex file) to support more than 65K Method references. When that happens, your code will generate build errors and won’t run.

You can learn more about this issue here: https://developer.android.com/tools/building/multidex.html

And a Few Methods More

When you compile your code and are short of the 65K limit, you may reasonably believe you don’t need to worry about this problem. That is, until you submit it to an Appstore. Most appstores, (the Amazon Appstore included), add additional method references as part of the ingestion process. If your code is ”too close” to the limit when submitted, your code may fail upon submitting to an Appstore after the additional references are added. This has always been the case. However, with the release of Android 5 (Lollipop) we have started seeing a lot more of these “too close” dex file problems. To help you avoid or work around this limitation, we have some suggestions below:

What Hitting the Wall Looks Like

You’ll know when your app references more than 65,535 methods because you’ll see an error something like this:

Or

If you see these errors, you can certainly address them before submitting to an Appstore. But even if you’re close, you’ll want to try some of these practices to stay comfortably away from “too close”.

How Close Are You to 65K Method References?

To find out how close you are to 65K method references, you can utilize a tool called dex-method-counts to get the method count and what is referencing them:

https://github.com/mihaip/dex-method-counts

What is “too close”?

“Too close” will be different for each Appstore and each device OS, so there is no single correct answer. But Google sets max methods to 60K if Multidex is used, so you can be pretty sure that 60K methods is a safe number for newer Android devices. (Devices running older Android OSs may need that limit closer to ~55K methods).

Use ProGuard to Help Remove Unused Libraries

The first (and easiest) step is to remove as many unnecessary libs and methods as possible. To help in this task, you can use ProGuard (part of the Android SDK) with -dontoptimize –dontobfuscate in the configuration which will remove unused methods from the dex file during build time. (See this helpful blog post on using ProGuard by Crashlytics)

Using More Than One dex File

If removing unused libraries doesn’t work for you, you can try using the Multi-dex approach, which splits up classes.dex into multiple dex files.

The quickest and safest approach for using multi-dex is to use the Multidex library with Gradle Plugin: https://developer.android.com/tools/building/multidex.html.

There are few caveats to this approach however; the main one is the requirement to use Gradle. You may also find that it may not remove enough methods to go below the limit without performing a few extra steps which are outlined in the “Using the Multidex Library” section below. You can use the dex-method-counts tool referenced above to check the method count of your resulting classes.dex file.

Using the Multidex Library

With Android 5.0 Lollipop release, a new support library (android-support-multidex.jar) appeared in Android SDK ver 21.1.x and Android Support library 21.0.3. You can find it in:

\android-sdk\extras\android\support\multidex\library\libs. It contains two new classes: MultiDex and MultiDexApplication and simplifies the Multidex loading process. According to Multidex documentation (http://developer.android.com/tools/building/multidex.html) it does not provide additional functionality on Android 5.0, which already has built-in support for secondary dex files. Rather, on previous versions of Android, it allows additional .dex files from the APK archive to the classloader. The library allows the archive to become part of the primary DEX file of your app and manages access to the additional DEX files.

To implement multi-dex for Pre-Android 5.0 releases follow the steps below:

Step #1

Make sure you have updated your Android build Tools to the latest version — You will need at least 21.1.x, current version as of this writing is 21.1.2

Step #2

Add the android-support-multidex.jar library into your project. You can find it in: \android-sdk\extras\android\support\multidex\library\libs

Step #3

Add multiDexEnabled true and Multidex dependency to your buildConfig in the build.gradle file. An example below:

Step #4

You can override the android.app.Application class, or declare MultiDexApplication class in AndroidManifest.xml file as shown below:

Step #5

If you have any additional libraries in your project, be sure that you disable pre-dexing on them. Unfortunately the — multi-dex option is not compatible with pre-dexed libs.

You can do this by adding the example below to your app/build.gradle file.

Step #6

You have to configure build instructions to endure that your Multidex app is optimized for the Amazon Appstore and our ingestion process. As of this writing you have three options:

Option #1 — Manually create the main-dex-list file.

In app/build.gradle file we have to add:

There are two params:

— multi-dex — enables splitting mechanism in build process

— main-dex-list — file with list of classes which have to be attached in main dex file (we will address this one in Step #5)

To ensure your Multidex app will ingest and publish properly in the Amazon Appstore you should use the — main-dex-list param to put the following in the main .dex file:

  • Custom Applications
  • Activities
  • Services
  • Receivers
  • Providers
  • Instrumentations
  • Annotations

Option #2 — Ignore the multi-dex and multi-dex-list parameters.

If you are using studio 0.9.0+ gradle 0.14.2 and use the dx.additionalParameters to manually set the max number of referenced methods in your main classes.dex file, then the main-dex-list will be auto-generated and you don’t have to set the multi-dex and multi-dex-list parameters. It will look similar to:

Option #3 — Ignore the multi-dex and multi-dex-list parameters if you are using studio 0.9.0+ gradle 0.14.2 and let the build tools automatically limit the dx.additionalParameters parameter to 60,000.

This should work for most applications, however if you have a very large number of classes in your app you may find that you will need to manually set your max number to something less than 60,000 to have your app ingest properly in the Amazon Appstore.

Additional Resources

StackOverflow has some handy info.

The source code of how Gradle automatically generates a main dex list is here.

There is also a tool that can automatically generate this main-dex-list here.

This blog post has an example of a useful proguard-rules.txt file that accommodates the AWS SDK and some other popular tools.

--

--

Mike Hines
Amazon Developers

Mobile app consultant by choice, frequent flyer by chance of profession. On a continuing mission to learn what's working in App Monetization. #gamedev