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


344

我以前见过各种版本的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

只有一个小技巧,您可能需要执行此操作,以防止在进行排序时内存不足。

dexOptions {
        javaMaxHeapSize "4g"
}

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

dexOptions {
        jumboMode true
}

更新:如果您的应用很胖,并且您的主应用中包含太多方法,则可能需要按照

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


1
您是否使用电流设备上不可用的api?

它在那里,因为另一个项目针对相同的API版本构建良好。
爱迪生

因此,您有时会使用不可用的API吗?您是否用类似if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)这样的行检查,如果不可用,则不调用此函数?
撤退

我愿意。该项目以前很好。另外,即使我错过了这一行,也应该是运行时错误。
爱迪生

这可能是依赖关系之一。(现在混合使用maven + project lib)
爱迪生

Answers:


379

更新3(11/3/2014)
Google终于发布了官方说明



适用于Android的Update 2( 2014年10月31日) Gradle插件v0.14.0 添加了对Multi-dex的支持。要启用,只需在build.gradle中声明它即可

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

如果您的应用程序支持5.0之前的Android(也就是说,如果您的minSdkVersion年龄为20或更低),则还必须动态修补应用程序ClassLoader,以便它能够从二级dexes加载类。幸运的是,有一个可以为您完成此任务。将其添加到应用程序的依赖项中:

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

您需要尽快调用ClassLoader补丁代码。MultiDexApplication该课程的文档建议了三种方法(选择其中一种)一种,最方便的一种):

1- MultiDexApplicationAndroidManifest.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- MultiDex#install通过您的Application#attachBaseContext方法进行调用:

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

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


Multi-dex支持解决了这个问题。dx 1.8已经允许生成多个dex文件。
Android L将原生支持多dex,并且支持库的下一个版本将涵盖API 4之前的较早版本。

Anwar Ghuloum 在 Android Developers Backstage播客集中对此进行了说明。我已经发布了相关部分的成绩单(和一般的多dex解释)。


2
博客文章是一个节省者!:D
nadavfima 2014年

39
蚀用户有什么用吗?
穆罕默德·巴巴尔

52
@MuhammadBabar有一个供Eclipse用户使用的Android Studio。
VipulKumar

2
@MohammedAli当然可以,请避免使用它。但是,如果您的应用程序中确实有太多方法,并且已经尝试了您提到的所有技巧,该怎么办?关于构建时间-有解决方案,至少对于开发构建-在这里查看我的答案:stackoverflow.com/a/30799491/1233652
Alex Lipov 2015年

2
在Android版Qt上,即使将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!

78

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

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

由于Google Play服务的20k +方法经常是“浪费”方法的主要嫌疑人之一。Google Play服务6.5或更高版本,您可以使用许多较小的客户端库在应用程序中包含Google Play服务。例如,如果仅需要GCM和地图,则可以选择仅使用以下依赖项:

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

子库的完整列表及其职责可以在Google官方文档中找到

更新:自支持库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则没有好处)

请参阅此处的官方发行说明以获取support-v4 lib


启用MultiDexing

由于Lollipop(又名构建工具21+),因此非常易于处理。该方法是解决每个dex文件65k方法的问题,以为您的应用创建多个dex文件。将以下内容添加到您的gradle构建文件中(文件取自具有超过65k方法的应用程序的官方google文档):

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

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

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

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

要么将其添加到您的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在构建阶段遇到异常,则可以使用

android {
    ...
    dexOptions {
        javaMaxHeapSize "4g"
    }
}

这会将堆设置为4 GB。

有关dex堆内存问题的更多详细信息,请参见此问题。


分析问题的根源

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

.\gradlew app:dependencies

有关Android中方法计数的更多信息,请参见此答案和问题


我使用了Play Services 6.5+解决方案,并且效果很好。令人难以置信的有用提示。非常感谢!
阮阮虎

如果可以的话,我会提出更多建议-消除所有其他我们未使用的Play服务内容,从而解决了这个问题,而不必诉诸于在构建时会对性能产生负面影响的多索引。
肖恩·巴尔博

1
比你好多,我的眼泪。您救了我
失眠症

我将客户端库用于GCM,因为我只使用play服务中的gcm服务,现在它解决了我的问题。谢谢!为了节省时间。
Ankit

57

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


我知道了。我对此项目确实有很多依赖。尽管在我使用Maven之前,它的构建还不错,也许Maven添加了不必要的依赖关系。将仔细检查。
爱迪生

5
更具体地说,每个Dalvik可执行文件(dex)文件只能有65,536个方法。一个应用程序(APK)可以具有多个dex文件,并具有自定义加载功能。
丹尼斯·谢尔

7
对于Android来说,这真是令人尴尬的错误!无论如何,以我为例,我删除了libs中没有使用的Jar,然后编译了该应用
David

是时候清理我的项目了:/
Decoy,2014年

1
一个快速的解决方法是将Proguard也与调试版本一起使用
aleb 2014年

12

如果您使用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
    }
}

爱它!像Google之类的公司不断扩大产品包装所需的清晰度。
爱迪生

1
很好-这确实完成了工作。不用麻烦,不用担心!
老虎机2014年

注意:此删除的Google Play服务会在我在Android Studio中的Android SDK中震撼!这是一个坏主意,因为要恢复到原始的罐子并不容易。作者应修改脚本以更改构建目录中的jar。
2014年

@inder:我没有那个问题。但是,clean每次确实要排除对象时,我都必须做一次(我们使用分析)。
JohnnyLambada 2014年

如何从发行版本中排除呢?
user1324936 2014年

6

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

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

https://github.com/mmin18/Dex65536


1
感谢您的脚本。您应该提防ART。设备只能转换您的默认dex,而不能转换第二个。Proguard解决方案应该是首选。
爱迪生

2
当我将项目导入Eclipse并运行时,它给出了错误。“无法执行dex:方法ID不在[0,0xffff]中:65536”。您能解释一下该项目的用途吗
Karacago 2014年

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云端硬盘API,这可行。
vedavis's

5

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

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}

2

完美的解决方案是与Proguard合作。正如评论中提到的aleb。它将使dex文件的大小减少一半。


1
同意,尤其是*(18k方法本身)具有越来越大的Google Play服务jar
爱迪生(Edison

2

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

建立->分析APK ..

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

您会看到:

在此处输入图片说明


0

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/**'
            }
        }
    }
  }
}

0

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


0

我今天也面临着同样的问题

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

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

希望能帮助到你


1
这对我有用-我只是禁用了“启用运行”,单击“应用”,将其重新启用,然后它再次起作用。
MrBigglesworth
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.