Android中每个dex文件的方法限制为64K [英] Limit of methods 64K per a dex file in Android

查看:66
本文介绍了Android中每个dex文件的方法限制为64K的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了这个问题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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆