I faced with this problem java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
and I decided to exclude some methods from a dex file. My gradle.build:
compile ('com.google.android.gms:play-services:+') {
exclude group: "com.google.android.gms.analytics"
exclude group: "com.google.android.gms.games"
exclude group: "com.google.android.gms.plus"
exclude group: "com.google.android.gms.drive"
exclude group: "com.google.android.gms.ads"
}
I think that this snippet of code is wrong, because there is error method ID not in [0, 0xffff]...
. How can I exclude unnecessary parts of Google Play Service? I use only maps and GCM.
Updated.
Thanks reVerse. It's really useful code. There is a script for getting count of methods (also can see names of existing packages) https://gist.github.com/JakeWharton/6002797 (source ./dex.sh; dex-method-count-by-package test.apk
)
Before using the snippet of code from reVerse's answer
Count of methods / Package
...
22484 com.google.android.gms
2 com.google.android.gms.actions
578 com.google.android.gms.ads
152 com.google.android.gms.ads.doubleclick
25 com.google.android.gms.ads.identifier
86 com.google.android.gms.ads.internal
86 com.google.android.gms.ads.internal.rawhtmlad
86 com.google.android.gms.ads.internal.rawhtmlad.client
88 com.google.android.gms.ads.mediation
4 com.google.android.gms.ads.mediation.admob
73 com.google.android.gms.ads.mediation.customevent
26 com.google.android.gms.ads.purchase
118 com.google.android.gms.ads.search
...
858 com.google.android.gms.games.internal.api
43 com.google.android.gms.games.internal.constants
8 com.google.android.gms.games.internal.data
31 com.google.android.gms.games.internal.events
9 com.google.android.gms.games.internal.experience
215 com.google.android.gms.games.internal.game
56 com.google.android.gms.games.internal.multiplayer
23 com.google.android.gms.games.internal.notification
80 com.google.android.gms.games.internal.player
86 com.google.android.gms.games.internal.request
...
After using the snippet of code from reVerse's answer, packages: ads, games and etc were deleted.
By adding this library, your app can manage the access of additional DEX files. In other words, if you are having more than 64K methods, then you will be having more than one DEX file and these DEX files will be managed by using this multidex support library.
Android applications by default have SingleDex support which limits your application to have only 65536 methods(references). So multidexEnabled = true simply means that now you can write more than 65536 methods(references) in your application.
With version 6.5 Google finally unbundled the Google Play Services. So from now on it'll be possible to selectively compile the APIs into your executable.
compile 'com.google.android.gms:play-services-wearable:6.5.+'
compile 'com.google.android.gms:play-services-ads:6.5.+'
For all the other individual Google Play Services APIs check this page on d.android.com.
Note: Using the +
is typically discouraged. As of now the current correct version would be 6.5.87
. For more information see the official Blog-Post (click).
Some time ago there's been an article on Medium.com called "[DEX] Sky’s the limit? No, 65K methods is" (definitely worth a read), which describes a way to strip the Google Play Services with a shell-script which you can find here (google-play-services-strip-script).
While this is an option, there's also a gradle task which does this for you:
def toCamelCase(String string) {
String result = ""
string.findAll("[^\\W]+") { String word ->
result += word.capitalize()
}
return result
}
afterEvaluate { project ->
Configuration runtimeConfiguration = project.configurations.getByName('compile')
ResolutionResult resolution = runtimeConfiguration.incoming.resolutionResult
// Forces resolve of configuration
ModuleVersionIdentifier module = resolution.getAllComponents().find { it.moduleVersion.name.equals("play-services") }.moduleVersion
String prepareTaskName = "prepare${toCamelCase("${module.group} ${module.name} ${module.version}")}Library"
File playServiceRootFolder = project.tasks.find { it.name.equals(prepareTaskName) }.explodedDir
Task stripPlayServices = project.tasks.create(name: 'stripPlayServices', group: "Strip") {
inputs.files new File(playServiceRootFolder, "classes.jar")
outputs.dir playServiceRootFolder
description 'Strip useless packages from Google Play Services library to avoid reaching dex limit'
doLast {
copy {
from(file(new File(playServiceRootFolder, "classes.jar")))
into(file(playServiceRootFolder))
rename { fileName ->
fileName = "classes_orig.jar"
}
}
tasks.create(name: "stripPlayServices" + module.version, type: Jar) {
destinationDir = playServiceRootFolder
archiveName = "classes.jar"
from(zipTree(new File(playServiceRootFolder, "classes_orig.jar"))) {
-----> // Specify what should be removed
}
}.execute()
delete {
delete (file(new File(playServiceRootFolder, "classes_orig.jar")))
}
}
}
project.tasks.findAll { it.name.startsWith('prepare') && it.name.endsWith('Dependencies') }.each { Task task ->
task.dependsOn stripPlayServices
}
}
Note: This is taken from Gradle task to strip unused packages on Google Play Services library @GitHubGist
The relevant part for you is where the arrow is in the task.create(...)
. There you need to specify which parts should be removed. So in your case just write something like this in there:
exclude "com/google/ads/**"
exclude "com/google/android/gms/analytics/**"
exclude "com/google/android/gms/games/**"
exclude "com/google/android/gms/panorama/**"
exclude "com/google/android/gms/plus/**"
exclude "com/google/android/gms/drive/**"
exclude "com/google/android/gms/ads/**"
exclude "com/google/android/gms/wallet/**"
exclude "com/google/android/gms/wearable/**"
This will remove everything except the Maps- and GCM-Part.
Note: In order to use it, just copy the contents of the gradle-task to the bottom of the build.gradle
file of your app module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With