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

时间:2013-03-04 19:46:00

标签: android dex

之前我见过各种版本的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;博士: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

12 个答案:

答案 0 :(得分:370)

更新3(11/3/2014)
谷歌终于发布了official description


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

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

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

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

您需要尽快调用ClassLoader修补程序代码。 MultiDexApplication班级library提出了三种方法(选择其中一个,一个对您来说最方便的方式):

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班级延长documentation班级:

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(2014年10月17日):
正如预期的那样,MultiDexApplication在Android支持库的修订版21中提供。你可以在/ sdk / extras / android / support / multidex / library / libs文件夹中找到android-support-multidex.jar。


Multi-dex支持解决了这个问题。 dx 1.8已经允许生成几个dex文件 Android L本身将支持multi-dex,支持库的下一版本将涵盖旧版本返回API 4.

Anwar Ghuloum在multidex support Android开发者Backstage播客节目中说明了这一点。我是相关部分的this(以及一般的多重解释)。

答案 1 :(得分:77)

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

防止问题:使用Play Services 6.5+和support-v4 24.2 +

减少方法的数量

由于Google Play服务通常是&#34;浪费&#34;的主要嫌疑人之一。方法及其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

更新:自Support Library 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'
}

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

将其添加到Application.java

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

使用mutlidex lib提供的应用程序

<?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千兆字节。

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

答案 2 :(得分:57)

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

答案 3 :(得分: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
    }
}

答案 4 :(得分:6)

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

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

https://github.com/mmin18/Dex65536

答案 5 :(得分: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' 

答案 6 :(得分:5)

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

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}

答案 7 :(得分:2)

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

答案 8 :(得分:2)

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

构建 - &gt;分析APK ..

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

你会看到:

enter image description here

答案 9 :(得分: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/**'
            }
        }
    }
  }
}

答案 10 :(得分:0)

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

答案 11 :(得分:0)

我今天面临着同样的问题,那就是下面的工作

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

在文件 - &gt;偏好设置 - &gt;构建,执行,部署 - &gt;即时运行 - &gt;选中启用即时运行热插拔...

希望有所帮助