1

UPDATE AGAINST DUPLICATE QUESTION:
I don't want to use multidex. There should be a solution without it, because the classes used by ":app" don't need this huge library bundle.

I'm currently working on a network project: application server and android client application. I've finished a pre-alpha version of the server and now I want to start coding the android client application.

My idea: I want to include the server git repository as a git submodule in my android project folder so gradle can use it as a dependency for my ':app' project.
BUT: The server repo uses jersey restful classes. So if I include the server gradle project as a dependency, the android build fails with the popular "Unable to execute dex: method ID not in [0, 0xffff]: 65536" error: DEX 65k Problem.

Well, my android client project don't use any class which needs jersey dependencies. There are only a few classes which includes parsing and handling methods for the data given by the server. I've included them in the server repo, so you always have the correct client classes for the actual server structure. If I create a second repo for client classes, they may not synced everytime.

How can I solve this? I thought about splitting the server repo in two gradle modules but the same git repo.

Any ideas??

PS: The 65k Problem: I always include classes in the android client project which have only java-own dependencies. Do the 65k means "available" or "used" methods?

1 Answers1

1

Using two Gradle modules sounds like the best solution, if you're using a few classes available from the server but not a majority of the server code. Java is very liberal in assembling the classpath, making available all classes that could possibly be used; however, this means that if you aren't careful about your classpath, the dexer is going to assume that all of those classes and methods should be made available in your dex, and convert much more than you actually need.

You may also consider enabling Proguard, which can trim down unused classes and methods and inline short methods. Both of these keep the class count down, though with some additional processing cost and some extra configuration. You'll especially need to be careful if you use reflection or native code, as Proguard may not be smart enough to detect methods that aren't called through normal Java calling semantics.


For further explanation about the limit (65,536 total method and field references) I definitely endorse Anubian Noob's link in the comments (How to shrink code - 65k method limit in dex). You should not switch to Multidex until absolutely necessary: All of the code will still need to be downloaded onto devices (and converted into OAT format on Lollipop devices and later), which will waste time and data if the code is strictly unnecessary. Instead, feed in the smallest possible input jar to the dexer, which implies splitting your modules or using Proguard.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Thank you for this great answer. I think splitting into two gradle modules are better. But can I configure ProGuard to only shirnk and not obfuscate? And when does ProGuard act - before compilation or after? I have only added "minifyEnabled" to my debug and release buildTypes. But then I get "unresolved references to library class members". :( –  Sep 04 '15 at 17:18
  • You're welcome! Yes, Proguard has a dizzyingly-expressive [configuration language](http://proguard.sourceforge.net/manual/usage.html) that allows you to enable or disable pruning, optimization, and obfuscation altogether or on a per-class/per-optimization basis. Proguard should run after `javac` but before `dx`, taking all your JARs as input and outputting a reduced JAR suitable for dexing into a compact APK. See the [Proguard gradle docs](http://proguard.sourceforge.net/manual/gradle.html) for more. – Jeff Bowman Sep 04 '15 at 17:25
  • Ok, great! Everytime using stackoverfloooow, I learn something. :) –  Sep 04 '15 at 17:26
  • One note, because I didn't say this clearly: Be sure to use the Proguard version and configuration built into Android, as in [the Android docs linked in the answer](http://developer.android.com/tools/help/proguard.html), rather than putting a Gradle task in there yourself. Internally Proguard converts a JAR to a smaller JAR, but Android will take care of that under the covers. – Jeff Bowman Sep 04 '15 at 17:35