避免提交应用程序时出现编译错误

避免提交应用程序时出现编译错误

如果您向亚马逊应用商店提交的应用程序引用了接近65000个方法,在提交之后,您可能会通过电子邮件或在“查看状态”选项卡上收到以下错误消息:

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

转换为Dalvik格式失败:无法执行dex:方法ID不在[0, 0xffff]中:65536

造成此错误的原因是,对于Dalvik可执行(dex)字节码文件,安卓的方法引用数限制为65535个。有关更多信息,请参阅安卓文档构建超过65K个方法的应用程序

亚马逊包装器

亚马逊会使用代码包装亚马逊应用商店中的每个应用程序,以便向开发者提供各种报告、分析、DRM和应用程序更新。此包装器为亚马逊库增加了1627个额外的引用方法,并为每个活动增加了9个额外的方法。由于这些额外的引用方法,如果您的应用程序引用了接近65000个方法,则可能会达到方法限制值。

虽然此限制始终存在,但随着Android 5.0 (Lollipop)的发布,该版本包括通常会增加应用程序可能引用的方法数的新功能,使得超过方法引用限制的情况日益常见。 

为了避免此限制,请考虑对方法引用计数并减少应用程序中的引用数。

对方法引用计数

要对应用程序引用的方法数量进行计数以及确定应用程序的哪些部分引用了方法,您可以使用GitHub上提供的dex-method-counts工具:https://github.com/mihaip/dex-method-counts

减少方法引用的数量

要减少方法引用的数量,请尝试尽可能地删除额外的库和方法。或者,您可以在配置中使用ProGuard和-dontoptimize –dontobfuscate,这会在生成时从dex文件中删除未使用的方法。

如果这些方法不适用于您的应用程序,请尝试使用multi-dex方法,这会将classes.dex拆分为多个dex文件。

您可以将multidex库与安卓Gradle插件配合使用。有关更多信息,请参阅构建超过65K个方法的应用程序

这种方法有几个注意事项:

  • 您必须使用Gradle进行安卓开发。
  • 您可能会发现,如果不执行下一部分中概述几个额外的步骤,Multidex不会删除足够的方法。

您可以使用上文所述的dex-method-counts工具来检查生成的classes.dex文件的方法计数。

使用Multidex库

在Android 5.0 Lollipop版本中,在安卓开发工具包版本21.1.x和安卓支持库21.0.3中提供了新的支持库(android-support-multidex.jar)。您可以在\android-sdk\extras\android\support\multidex\library\libs中找到此支持库。它包含两个新类:MultiDexMultiDexApplication,并简化了multidex加载过程。

如果您的应用程序专门面向Android 5.0,则无需使用此库,因为Android 5.0提供对第二个dex文件的内置支持。不过,在安卓的早期版本中,它会将额外的.dex文件从APK档案添加到类加载器。该库允许档案成为应用程序主DEX文件的一部分,并管理对其他DEX文件的访问。因此,如果您的应用程序面向任何早于Android 5.0的安卓版本,应使用此库。

为Android 5.0之前的应用程序实施此解决方案:

  1. 确保您已将安卓构建工具更新到最新版本。您至少需要版本21.1.x。编写本文时的最新版本为21.1.2。
  2. android-support-multidex.jar库添加到您的项目中。可以在\android-sdk\extras\android\support\multidex\library\libs中找到它。
  3. multiDexEnabled trueMultidex dependency添加到build.gradle文件的buildConfig中,如以下示例中所示。

    android {
        compileSdkVersion 21
        buildToolsVersion "21.1.2"
    
        defaultConfig {
            ...
            minSdkVersion 14
            targetSdkVersion 21
            ...
            // 启用multidex支持。
            multiDexEnabled true
    }
     ...
    }
    dependencies {
        compile 'com.android.support:multidex:1.0.0'
    } 
    
  4. 覆盖android.app.Application,或者在AndroidManifest.xml文件中声明MultiDexApplication类,如以下代码中所示:

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
    
  5. 如果您在项目中有任何其他库,请确保对这些库禁用了预编译dex功能。遗憾的是,--multi-dex选项与已预编译dex的库不兼容。

    您可以将以下代码添加到app/build.gradle文件中来禁用预编译dex功能。

    android {
    //  ...
        dexOptions {
            preDexLibraries = false
            additionalParameters = ["--set-max-idx-number=55000"] // default 60000
        }
    }
    
  6. 配置生成指令,确保multidex应用程序针对亚马逊应用商店和提交流程进行了优化。您有三个选项:

    1. 手动创建main-dex-list文件。在app/build.gradle文件中,添加以下内容:

      afterEvaluate {
          tasks.matching {
              it.name.startsWith('dex')
          }.each { dx ->
              if (dx.additionalParameters == null) {
                  dx.additionalParameters = []
              }
              dx.additionalParameters += '--multi-dex'
              dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString()
          }
      }
      

      此代码使用两个参数:

      • --multi-dex –在生成过程中启用拆分机制。
      • --main-dex-list –具有必须附加到主dex文件中的类列表的文件。

      为了确保multidex应用程序将正确完成提交流程并发布到亚马逊应用商店中,您应使用--main-dex-list参数将以下内容放在主.dex文件中:

      • 自定义应用程序
      • 活动
      • 服务
      • 接收方
      • 提供方
      • 工具
      • 注释
    2. 如果您使用studio 0.9.0+ gradle 0.14.2并使用dx.additionalparameters在主classes.dex文件中手动设置引用方法的最大数量,则忽略multi-dexmulti-dex-list参数。将自动生成main-dex-list。它将类似于以下内容:

      afterEvaluate {
          tasks.matching {
              it.name.startsWith('dex')
          }.each { dx ->
              if (dx.additionalParameters == null) {
                  dx.additionalParameters = []
              }
              dx.additionalParameters += "--set-max-idx-number=55000" // default 60000
          }
      }
      
    3. 如果您使用的是0.9.0+ gradle 0.14.2并让构建工具自动将dx.additionalParameters参数限制为60000个,则忽略multi-dexmulti-dex-list参数。这应该适用于大多数应用程序,但是,如果您的应用程序中有数量非常多的类,您可能会发现需要手动将最大数量设置为某个小于60000的值,以便让应用程序正确完成提交到亚马逊应用商店的过程。

其他资源

要生成main-dex-list,可以参考以下帮助: