Android中每个dex文件的方法限制为64K [英] Limit of methods 64K per a dex file in Android
问题描述
我遇到了这个问题java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
,因此决定从dex文件中排除某些方法.我的gradle.build:
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"
}
我认为此代码段是错误的,因为存在错误method ID not in [0, 0xffff]...
.如何排除Google Play服务不必要的部分?我只使用地图和GCM.
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.
已更新.
感谢reVerse.这是非常有用的代码.有一个脚本可以获取方法数量(也可以查看现有包的名称) https://gist.github.com/JakeWharton/6002797 (source ./dex.sh; dex-method-count-by-package test.apk
)
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
)
在使用reVerse的答案中的代码段之前
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
...
使用reVerse的答案中的代码段后,广告,游戏等软件包被删除.
After using the snippet of code from reVerse's answer, packages: ads, games and etc were deleted.
推荐答案
更新-Google Play服务6.5(12-08-14)
在6.5版中,Google最终取消了对Google Play服务的捆绑.因此,从现在开始,可以有选择地将这些API编译到您的可执行文件中.
Update - Google Play Services 6.5 (12-08-14)
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.+'
对于其他所有单独的Google Play服务API,请 d.android.com上的此页面.
For all the other individual Google Play Services APIs check this page on d.android.com.
注意:通常不建议使用+
.截至目前,当前的正确版本为6.5.87
.有关更多信息,请参见官方博客文章(点击).
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).
前段时间,在 Medium.com 上有一篇名为(绝对值得一读),它描述了一种 strip Google使用Shell脚本播放服务,您可以在此处(google-play-services-strip-script).
虽然这是一个选项,但还有一个 gradle任务可以为您完成此任务:
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
}
}
注意::此操作取自 Gradle任务,以剥离Google Play服务库@GitHubGist上未使用的包./a>
Note: This is taken from Gradle task to strip unused packages on Google Play Services library @GitHubGist
与您相关的部分是task.create(...)
中箭头的位置.您需要在此处指定要删除的部分.因此,在您的情况下,只需在其中写这样的内容即可:
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/**"
这将删除除地图部分和GCM零件以外的所有内容.
This will remove everything except the Maps- and GCM-Part.
注意:要使用它,只需将gradle-task的内容复制到应用模块的build.gradle
文件的底部.
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.
这篇关于Android中每个dex文件的方法限制为64K的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!