无法执行 dex:方法 ID 不在 [0, 0xffff] 中:65536

Posted

技术标签:

【中文标题】无法执行 dex:方法 ID 不在 [0, 0xffff] 中:65536【英文标题】:Unable to execute dex: method ID not in [0, 0xffff]: 65536 【发布时间】:2013-02-19 00:42:26 【问题描述】:

我以前见过各种版本的 dex erros,但这个是新的。清理/重启等无济于事。图书馆项目似乎完好无损,并且依赖关系似乎正确链接。

Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

Cannot merge new index 65950 into a non-jumbo instruction

java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536

tl;dr:Google 的官方解决方案终于来了!

http://developer.android.com/tools/building/multidex.html

只有一个小提示,您可能需要这样做以防止在进行 dex-ing 时出现内存不足。

dexOptions 
        javaMaxHeapSize "4g"

还有一种巨型模式可以以不太可靠的方式解决此问题:

dexOptions 
        jumboMode true

更新:如果您的应用程序很胖并且您的主应用程序中有太多方法,您可能需要按照以下方式重新组织您的应用程序

http://blog.osom.info/2014/12/too-many-methods-in-main-dex.html

【问题讨论】:

您是否使用当前设备上不可用的 api? 它就在那里,因为另一个项目构建良好,针对相同的 API 版本。 所以您在某些时候使用了不可用的 API?你是否检查了if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 这样的行,如果它不可用,你就不会调用它? 是的,我愿意。该项目之前构建良好。此外,即使我错过了这条线,这也应该是一个运行时错误。 可能是其中一个依赖项搞砸了。 (现在混合使用 maven+project lib) 【参考方案1】:

更新 3(2014 年 11 月 3 日) 谷歌终于发布了official description。


更新 2(2014 年 10 月 31 日) Gradle 插件 v0.14.0 for Android adds support for multi-dex。要启用,您只需在 build.gradle 中声明它:

android 
   defaultConfig 
      ...
      multiDexEnabled  true
   

如果您的应用程序支持 5.0 之前的 Android(即,如果您的 minSdkVersion 为 20 或更低),您还必须动态修补 应用程序 ClassLoader,以便它能够加载类从二级索引。幸运的是,有一个 library 可以为您做到这一点。将其添加到您应用的依赖项中:

dependencies 
  ...
  compile 'com.android.support:multidex:1.0.0'
 

您需要尽快调用 ClassLoader 补丁代码。 MultiDexApplication 班级的 documentation 建议了三种方法(选择其中一种,一种对您来说最方便的方法):

1 - 将MultiDexApplication 类声明为您的AndroidManifest.xml 中的应用程序:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

2 - 让您的 Application 类扩展 MultiDexApplication 类:

public class MyApplication extends MultiDexApplication  .. 

3 - 从您的 Application#attachBaseContext 方法调用 MultiDex#install

public class MyApplication 
    protected void attachBaseContext(Context base) 
        super.attachBaseContext(base);
        MultiDex.install(this);
        ....
    
    ....


更新 1(2014 年 10 月 17 日): 正如预期的那样,multidex support 在 Android 支持库的修订版 21 中提供。您可以在 /sdk/extras/android/support/multidex/library/libs 文件夹中找到 android-support-multidex.jar。


多 dex 支持解决了这个问题。 dx 1.8 已经允许生成多个 dex 文件。 Android L 将原生支持 multi-dex,支持库的下一个版本将覆盖旧版本回到 API 4。

在 Anwar Ghuloum 的 this Android Developers Backstage 播客节目中有所说明。我有相关部分的posted a transcript(和一般多索引解释)。

【讨论】:

博客文章是一个保护者! :D Eclipse 用户有什么用? @MuhammadBabar Eclipse 用户有 Android 工作室。 @MohammedAli 当然,如果可以,请避免使用它。但是,如果您的应用程序中真的有太多方法,并且您已经尝试过您提到的所有技巧,您应该怎么做?关于构建时间 - 有解决方案,至少对于开发构建 - 在这里查看我的答案:***.com/a/30799491/1233652 在 Qt for Android 上,当我将 Facebook+Twitter 的 SDK 集成在一起时,我的应用程序在运行时遇到了问题,即使在启用了 multidex 支持之后也是如此(这一错误尤其让我做噩梦:java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/vendor/lib, /system/lib]])。事实证明,我的错误是我没有为 5.0 之前的 Android 支持应用额外的步骤。话虽如此,选项#3 解决了它,我没有更多的ClassNotFoundException 问题。谢谢@Alex Lipov!【参考方案2】:

如前所述,您的项目和库中有太多方法(超过 65k)。

预防问题:使用 Play Services 6.5+ 和 support-v4 24.2+ 减少方法数量

由于 Google Play 服务通常是其20k+ methods 的“浪费”方法的主要嫌疑人之一。 Google Play 服务版本 6.5 或更高版本,您可以包含 Google Play services in your application using a number of smaller client libraries. 例如,如果您只需要 GCM 和地图,您可以选择仅使用这些依赖项:

dependencies 
    compile 'com.google.android.gms:play-services-base:6.5.+'
    compile 'com.google.android.gms:play-services-maps:6.5.+'

The full list of sub libraries and it's responsibilities can be found in the official google doc.

更新:自支持库 v4 v24.2.0 以来,它被拆分为以下模块:

support-compatsupport-core-utilssupport-core-uisupport-media-compatsupport-fragment

dependencies 
    compile 'com.android.support:support-fragment:24.2.+'

但是请注意,如果您使用support-fragment,它将依赖于所有其他模块(即,如果您使用android.support.v4.app.Fragment,则没有任何好处)

See here the official release notes for support-v4 lib


启用 MultiDexing

自从 Lollipop(又名构建工具 21+)以来,它非常容易处理。该方法是解决每个 dex 文件 65k 个方法的问题,为您的应用程序创建多个 dex 文件。将以下内容添加到您的 gradle 构建文件 (this is taken from the official google doc on applications with more than 65k methods):

android 
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig 
        ...
        // Enabling multidex support.
        multiDexEnabled true
    
    ...


dependencies 
  compile 'com.android.support:multidex:1.0.1'

第二步是准备您的应用程序类,或者如果您不扩展应用程序,请在您的 Android 清单中使用 MultiDexApplication

要么将它添加到您的 Application.java 中

@Override
  protected void attachBaseContext(Context base) 
    super.attachBaseContext(base);
    MultiDex.install(this);
  

使用 mutlidex 库中提供的应用程序

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

使用 MultiDex 防止 OutOfMemory

​​>

作为进一步的提示,如果您在构建阶段遇到 OutOfMemory 异常,您可以使用以下方法扩大堆

android 
    ...
    dexOptions 
        javaMaxHeapSize "4g"
    

这会将堆设置为 4 GB。

See this question for more detail on the dex heap memory issue.


分析问题根源

为了分析方法的来源,gradle 插件https://github.com/KeepSafe/dexcount-gradle-plugin 可以帮助结合 gradle 提供的依赖树,例如

.\gradlew app:dependencies

See this answer and question for more information on method count in android

【讨论】:

我使用了 Play Services 6.5+ 解决方案,它运行良好。令人难以置信的有用提示。非常感谢! 如果可以的话,我会支持更多 - 删除我们未使用的所有其他 Play Services 东西修复了这个问题,而不必求助于 multi-dex,这会对性能产生负面影响建设。 比起你,我眼里含着泪水。你救了我 我使用 GCM 的客户端库,因为我只使用来自 play 服务的 gcm 服务,现在它解决了我的问题。谢谢!为了节省我的时间。【参考方案3】:

您的项目太大。你的方法太多了。每个应用程序只能有 65536 个方法。看这里https://code.google.com/p/android/issues/detail?id=7147#c6

【讨论】:

我明白了。我确实对这个项目有很多依赖。在我开始使用 maven 之前它构建得很好,也许 maven 添加了不必要的依赖项。将仔细检查。 更具体地说,每个 Dalvik 可执行 (dex) 文件只能有 65,536 个方法。一个应用程序 (APK) 可以有多个 dex 文件,包括自定义加载。 真是个尴尬的安卓bug!无论如何,在我的情况下,我删除了库中未使用的 Jar,并编译了应用程序 是时候清理我的项目了:/ 一个快速的解决方法是在调试版本中也使用 Proguard【参考方案4】:

如果您使用 Gradle,以下代码会有所帮助。允许您轻松删除不需要的 Google 服务(假设您正在使用它们)以恢复到 65k 阈值以下。这篇文章的所有功劳:https://gist.github.com/dmarcato/d7c91b94214acd936e42

编辑 2014-10-22:关于上面提到的要点有很多有趣的讨论。 TLDR?看这个:https://gist.github.com/Takhion/10a37046b9e6d259bb31

将此代码粘贴到您的 build.gradle 文件底部并调整您不需要的 google 服务列表:

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"))) 
                    exclude "com/google/ads/**"
                    exclude "com/google/android/gms/analytics/**"
                    exclude "com/google/android/gms/games/**"
                    exclude "com/google/android/gms/plus/**"
                    exclude "com/google/android/gms/drive/**"
                    exclude "com/google/android/gms/ads/**"
                
            .execute()
            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
    

【讨论】:

爱它! def 需要,因为像 Google 这样的公司一直在夸大这些软件包。 很好 - 这确实完成了工作。不用麻烦,不用担心! 注意:这删除了我在 Android Studio 中的 Android SDK 中的 google play services jars!一个坏主意,因为恢复到原来的罐子并不容易。作者应该修改脚本以更改构建目录中的jar。 @inder:我没有这个问题。但是,每次我使用排除项(我们使用分析)时,我都必须做一个clean 如何从发布版本中排除这个?【参考方案5】:

我分享了一个示例项目,它使用 custom_rules.xml 构建脚本和几行代码解决了这个问题。

我在自己的项目中使用了它,它可以在 1M+ 设备上完美运行(从 android-8 到最新的 android-19)。希望对您有所帮助。

https://github.com/mmin18/Dex65536

【讨论】:

感谢脚本。你应该注意ART。设备可能只转换您的默认 dex 而不是辅助的。应该首选 Proguard 解决方案。 当我将项目导入 Eclipse 并运行时会出错。 “无法执行 dex:方法 ID 不在 [0, 0xffff] 中:65536”。你能解释一下项目的用途吗【参考方案6】:

遇到同样的问题并通过在依赖项部分编辑我的 build.gradle 文件来解决它,删除:

compile 'com.google.android.gms:play-services:7.8.0'

并将其替换为:

compile 'com.google.android.gms:play-services-location:7.8.0'
compile 'com.google.android.gms:play-services-analytics:7.8.0' 

【讨论】:

完美!我只使用了 Google Drive API,这很有效。【参考方案7】:

尝试在 build.gradle 中添加以下代码,它对我有用 -

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig 
    multiDexEnabled true

【讨论】:

【参考方案8】:

完美的解决方案是使用 Proguard。正如评论中提到的阿莱布。 它会将 dex 文件的大小减少一半。

【讨论】:

同意,尤其是越来越大的 google play services jar *(18k 方法本身)【参考方案9】:

您可以使用 Android Studio 分析问题(dex 文件引用):

构建 -> 分析 APK ..

在结果面板上点击 classes.dex 文件

你会看到:

【讨论】:

【参考方案10】:

gradle + proguard 解决方案:

afterEvaluate 
  tasks.each 
    if (it.name.startsWith('proguard')) 
        it.getInJarFilters().each  filter ->
            if (filter && filter['filter']) 
                filter['filter'] = filter['filter'] +
                        ',!.readme' +
                        ',!META-INF/LICENSE' +
                        ',!META-INF/LICENSE.txt' +
                        ',!META-INF/NOTICE' +
                        ',!META-INF/NOTICE.txt' +
                        ',!com/google/android/gms/ads/**' +
                        ',!com/google/android/gms/cast/**' +
                        ',!com/google/android/gms/games/**' +
                        ',!com/google/android/gms/drive/**' +
                        ',!com/google/android/gms/wallet/**' +
                        ',!com/google/android/gms/wearable/**' +
                        ',!com/google/android/gms/plus/**' +
                        ',!com/google/android/gms/topmanager/**'
            
        
    
  

【讨论】:

【参考方案11】:

从Libs文件夹中删除一些jar文件并复制到其他文件夹,然后转到_Project Properties>选择Java Build Path,选择Libraries,选择Add External Jar,选择Removed jar到您的项目,点击保存,这将是添加在引用库而不是 Libs 文件夹下。现在清理并运行您的项目。您不需要为 MultDex 添加任何代码。它对我很有效。

【讨论】:

【参考方案12】:

我今天也遇到了同样的问题,解决方法如下

对于 ANDROID STUDIO...启用即时运行

在 File->Preferences->Build, Execution, Deployment->Instant Run-> 勾选 Enable Instant run for hot swap...

希望对你有帮助

【讨论】:

这对我有用 - 我只是禁用了启用运行,单击应用,重新启用它,它再次工作。

以上是关于无法执行 dex:方法 ID 不在 [0, 0xffff] 中:65536的主要内容,如果未能解决你的问题,请参考以下文章

Google iosched:com.android.dex.DexIndexOverflowException:方法 ID 不在

Android Studio DexIndexOverflowException:方法 ID 不在

使用 libgdx 应用在 Eclipse 中启用 multidex

无法执行dex:多个dex文件定义了Lorg/apache/cordova/App$1

Android Studio 3.0 任务执行失败:无法合并 dex

Android Unable to execute dex: method ID not in [0, 0xffff]: 65536 问题解决方法