引用超过65000个方法的编译错误
由于字节编码文件中的Dalvid执行限制,引用方法数接近65000的应用程序,在提交到应用商店时会遇到编译错误。
引用超过65000个方法的构建错误
如果您向亚马逊应用商店提交的应用程序引用了接近65000个方法,在提交之后,您可能会通过电子邮件或在“查看状态”选项卡上收到以下错误消息:
Unable to execute dex: method ID not in [0, 0xffff] (无法执行dex:方法ID不在[0, 0xffff]中): 65536
Conversion to Dalvik format failed (转换为Dalvik格式失败): Unable to execute dex: method ID not in [0, 0xffff] (无法执行dex:方法ID不在[0, 0xffff]中): 65536
造成此错误的原因是,对于Dalvik可执行(dex)字节码文件,安卓的方法引用数限制为65535个。有关更多信息,请参阅安卓文档中的构建超过65K个方法的应用程序。
从亚马逊包装器中添加的其他方法
亚马逊会使用代码包装亚马逊应用商店中的每个应用程序,以便向开发者提供各种报告、分析、DRM和应用程序更新。此包装器为亚马逊库增加了1627个额外的引用方法,并为每个活动增加了9个额外的方法。由于这些额外的引用方法,如果您的应用程序引用了接近65000个方法,则可能会达到方法限制值。
虽然此限制始终存在,但随着安卓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个方法的应用程序。
使用Multidex方法时请注意以下事项:
- 您必须使用Gradle进行安卓开发。
- 您可能会发现,如果不执行几个额外的步骤(在下一部分中概述),Multidex不会删除足够的方法。
您可以使用上文所述的dex-method-counts工具来检查生成的classes.dex
文件的方法计数。
使用Multidex库
使用安卓5.0 Lollipop,在安卓开发工具包21.1.x版和安卓支持库21.0.3中会显示支持的库(称为android-support-multidex.jar
)。您可在\android-sdk\extras\android\support\multidex\library\libs
中找到此支持库。它包含两个新类MultiDex
和MultiDexApplication
,并简化了multidex加载过程。
如果您的应用程序专门面向安卓5.0,则无需使用此库,因为安卓5.0提供对第二个dex文件的内置支持。不过,在早期版本中,安卓会将额外的.dex
文件从APK档案添加到类加载器。该库允许档案成为应用程序主DEX文件的一部分,并管理对其他DEX文件的访问。因此,如果您的应用程序面向任何早于安卓5.0的安卓版本,应使用此库。
为安卓5.0之前的应用程序实施此解决方案:
- 确保您已将安卓构建工具更新到最新版本。您至少需要21.1.x版本或更高版本。
- 将
android-support-multidex.jar
库添加到您的项目中。可以在\android-sdk\extras\android\support\multidex\library\libs
中找到它。 -
将
multiDexEnabled true
和Multidex 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' }
-
覆盖类
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>
-
如果您在项目中有任何其他库,请确保对这些库禁用了预编译dex功能。遗憾的是,
--multi-dex
选项与已预编译dex的库不兼容。您可以将以下代码添加到
app/build.gradle
文件中来禁用预编译dex功能:android { // ... dexOptions { preDexLibraries = false } }
注意: 以前,您可以通过在dexOptions
下添加额外的属性来设置单个dex文件的最大方法数,如下所示:additionalParameters = ["--set-max-idx-number=55000"]
。但是,使用新的安卓编译器D8和Android studio 3.1.2,–set-max-idx-number
不再有效。因此,如果您包括此属性,则在应用程序提交过程中会出现错误。 -
配置生成指令,确保multidex应用程序针对亚马逊应用商店和提交流程进行了优化。您有两个选项:
-
手动创建
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
文件中:- 自定义应用程序
- 活动
- 服务
- 接收方
- 提供方
- 工具
- 注释
-
如果您使用的是studio 0.9.0+ gradle 0.14.2并让构建工具自动将
dx.additionalParameters
参数限制为60000
个,则忽略multi-dex
和multi-dex-list
参数。这应该适用于大多数应用程序,但是,如果您的应用程序中有数量非常多的类,您可能会发现需要手动将最大数量设置为小于60000的值,以便让应用程序正确完成提交到亚马逊应用商店的过程。
-
确保AndroidX库未混淆
如果您为multidexing使用AndroidX 库,请通过在Proguard文件中添加此行来确保AndroidX库未混淆:
-keep class androidx/multidex.** { *; }
其他资源
有关生成main-dex-list
的帮助,请参阅以下内容:
- CreateManifestKeepList.groovy – 这是Gradle如何自动生成
main-dex-list
的源代码。 - 一个可自动生成此main-dex-list的工具。