安卓:我的应用程序太大,"Unable to execute dex: method ID not in [0, 0xffff]: 65536"?



我正在尝试将我的应用程序与Box, Dropbox和Google Drive集成。所有这3个服务都需要大量的第三方jar。此外,我的应用程序已经需要一些第三方jar。现在,当我尝试从eclipse运行我的应用程序时,我得到以下错误:

无法执行索引:方法ID不在[0,0xffff]: 65536转换to Dalvik格式失败:无法执行索引:方法ID不在[0],

0 xffff]: 65536

似乎这个错误发生是因为我的应用程序有太多的方法。我相当确定这些方法中的大部分来自第三方jar,因此试图通过简化代码来解决这个问题是不现实的。我在网上找到了这两个建议。

  1. add dex.force.jumbo=true to project。属性(并使用adt版本21)。我这样做,但仍然得到错误。

  2. 使用多个索引文件,如下所示:http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html。这似乎是唯一的选择,但我不明白它如何适用于我的情况。问题是像Drive这样的服务有太多的依赖关系。这个解决方案不需要我修改Drive源,以便在引用其依赖项时使用inflection吗?

  3. 使用proguard收缩删除未使用的代码/方法。使用proguard导出我的应用程序确实可以工作,并且文档服务集成在>4.0的设备上按预期工作。但是,在2.3设备上测试时会抛出classnotfound错误。

所以,我希望在这个问题上得到一些建议。选项2适合我的情况吗?我应该考虑其他解决方案吗?

你也可以开发一个或多个插件到你的主应用程序中,以一个单独的APK的形式提供下载。APK将暴露主应用程序将使用的一些组件——由于我不知道您与这些服务集成的性质,因此我无法对此提出更具体的建议。您将使用自己的signature级别自定义<permission>来保护两个应用程序之间的通信。而且,作为奖励,如果使用第三方库增加了对额外权限的要求,您将只需要在插件APK中使用这些权限,使您的主APK更小。

***NEW****所有其他答案现在都过时了。下面是新的修复

Android 5.0及以上版本

自动包含多索引支持。来自文档:

Android 5.0及更高版本使用ART运行时支持从应用程序APK文件加载多个dex文件。艺术在应用程序安装时执行预编译,扫描classes(..N). index文件,并将它们编译成一个.oat文件由Android设备执行。有关Android的更多信息5.0运行时,参见介绍ART。

Android 5.0以下版本

只需在gradle构建中添加Android多索引支持工具:

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"
    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...
        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}
dependencies {
  compile 'com.android.support:multidex:1.0.0'
}

Dalvik虚拟机每个索引文件最多可以有65536个方法,因为字节码指令集没有办法引用需要超过16位的方法号(正如@danfuzz在评论中指出的)。

虽然可以使用多个dex文件来解决这个问题,但Facebook发现了另一个修复方法,他们可以在应用程序中部署来解决这个问题。

查看vm/linearallocc .c,您可以找到以下代码:(Android 2.3.3下5MiB, Android 4.0后8MiB作为我的调查)

#define DEFAULT_MAX_LENGTH (5*1024*1024)

LinearAllocHdr * pHdr;

pHdr->mapLength = DEFAULT_MAX_LENGTH;

我想'Facebook修复'是通过使用本机C指针编辑此内存。我认为线性分配问题和这个方法ID问题是不同的。

我最近遇到了这个问题。在网上搜索了一些更详细的实现后,我意识到除了:

  • 很好,但现在Gradle已经过时了:http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html
  • 没有太多细节,但对如何做到这一点有一个模糊的想法:https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920

我意识到问题不一定是我的代码中有太多的方法,而是我的代码和其他库的完整dex是问题所在。所以,如果我可以编译我的代码针对库,但不包括它们在classes.dex,然后dex库分开,然后把它放在一起在运行时,它应该工作。唯一需要解决的问题是类加载器,这是Facebook在传递中提到的。

因此,通过一些反思和Groovy代码,我想我想出了一个相对稳定的方法,将库和应用程序代码打包到单独的dex文件中。

https://gist.github.com/nickcaballero/7045993

达到65k方法限制的大多数问题都与在应用程序中使用乳齿牙Google Play Services有关。最近,您可以在使用它时获得更多粒度。

按照本指南,您只能使用您想要的部件。也许这将解决问题,避免一些黑魔法的把戏,或使用multiDex。例如,如果你只想在你的应用中使用谷歌地图(并且你没有使用广告,钱包,Google wear,分析等),那么使用整个依赖项是浪费时间/空间。你可以这样使用:

compile com.google.android.gms:play-services-base:6.5.87
compile com.google.android.gms:play-services-maps:6.5.87

您可以在此链接中阅读完整的"部件"列表

这是我编写的一个脚本,用于计算特定文件夹中每个jar(和总数)中的方法数量。

一旦你计算了方法,你就可以专注于重构和删除繁重的库。

您需要为此启用Dex支持。因此,您需要执行以下步骤:

  1. Gradle plugin v0.14.0 for Android增加了对多索引的支持。要启用它,你只需要在build.gradle中声明它:
android {
   defaultConfig {
      ...
      multiDexEnabled = true
   }
}
  • 如果应用程序支持> 5.0(也就是说,如果你的minSdkVersion是20或以下),你还必须动态地修补应用程序ClassLoader,所以它将能够从二级索引加载类。为此,您可以添加这个库。
  •  dependencies {
          ...
          compile 'com.android.support:multidex:1.0.0'
        }
    
  • 在代码中启用这些选项。选择一个最适合你的
  • 。在manifest manifest

    中添加MultiDexApplication
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.App"> <application
    android:name="android.support.multidex.MultiDexApplication">
    </application>
    </manifest>
    

    B。通过MultiDexApplication扩展应用程序

    public class App extends MultiDexApplication { .. }
    

    C。

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

    更多信息请访问此链接MultiDex

    最新更新