本文翻译自http://developer.android.com/intl/zh-cn/tools/building/multidex.html#about。主要介绍当我们Android App中函数超过65536时构建失败的原因及解决办法!

-------------------------分割线--------------------------------------------------

随着android platform的持续增长,android apps的大小也在增长。当你的应用程序包括其所引用的库达到一定的规模,你将遇到构建错误,这表明你的程序已经达到到了android 应用框架的限制。在早期的构建系统会报告如下错误信息:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

最近版本的构建系统会显示不同的错误,这是同一个问题的提示信息:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

这两种错误情况显示了一个共同的数字:65536。这个数字代表的是单个Dalvik可执行的(DEX)字节码文件的可以调用方法总数。如果你已经创建了android应用,并且收到了这个错误,那么恭喜你,你的代码太多了!本文档将介绍如何突破这个限制,继续构建你的app。

About the 65K Reference Limit

APK文件包含用于运行你的应用程序编译代码形式的可执行字节码文件(Dalvik Executable DEX)。Dalvik可执行的规范限制了在一个单一的DEX文件中引用到包括Android框架方法,库方法等方法的总数为65,536。想要突破此限制,您需要配置您的应用程序的构建过程,生成多个DEX文件,被称为multidex配置。

Multidex support prior to Android 5.0

Android5.0之前的版本使用的Dalvik运行时执行应用程序代码。默认情况下,Dalvik的限制的应用程序,每APK一个classes.dex字节码文件。为了解决这个限制,可以使用multidex support library,成为您的应用程序的主DEX文件的一部分,然后设法获得了额外的DEX文件和它们所包含的代码。

Multidex support for Android 5.0 and higher

Android5.0以及更高版本使用的是ART runtime,可以支持原生从APK文件中加载多个dex文件。ART进行预编译的应用程序安装时它会扫描类(.. N).dex文件,并通过Android设备编译成一个单一的.oat文件执行。对于在Android5.0运行时的详细信息,请参考 Introducing ART

Avoiding the 65K Limit

在配置您的应用程序能够使用65K+方法个数之前,您应该采取措施来减少您的应用程序代码调用引用的总数,包括您的应用程序代码中的方法和库定义的方法。以下策略可以帮助您避免超过DEX参考限值:

看您的应用程序的直接和间接性依赖:确保在你的app中包含的library的用途要和其代码量匹配。一个比较常见的反例就是包含巨大的代码量,用途却很小。减少你的app的library依赖往往可以帮你避免dex reference限制。

删除未使用的代码混淆(code with ProGuard:配置可以运行你的app的ProGuard并确保可以在正式构建程序的时候为你的程序瘦身。

使用这些技术可以帮助你避免更改程序构建配置时需要启用更多的方法引用。对于宽带成本很高的市场来说,这些步骤很重要。

Configuring Your App for Multidex with Gradle

Android插件Gradle 可Android SDK Build Tools 21.1和更高版本中支持multidex作为构建配置的一部分。在为你app配置multidex之前,请先使用SDK Manager将Android SDKBuild Tools 和Android Support Repository更新到最新版本。

在你的app中使用multidex配置之前,需要对你的程序开发做一些相应修改。你需要执行以下步骤:

1.修改你的 Gradle构建配置以启用multidex

2.修改你的AndroidManifest 去引用MultiDexApplication class。

修改build.gradle配置去引用support library和启用multidex输出,如以下所示build.gradle片段

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

      Note:你可以在build.gradle文件的defaultConfig,buildType,或者productFlavor中设置multiDexEnable。

在你的AndroidManifest的application元素中添加MultiDexApplication class:

<?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>

当这些配置添加到一个应用程序中,Android构建工具会构建一个dex(classes.dex),根据需要会继续构建(classes2.dex, classes3.dex)。然后构建系统将他们打包进同一个apk中。

      Note: 如果你的app使用了自己定义的Application class,你可以重写attachBaseContext()方法并在其中调用MultiDex.install(this)去实现multidex。更多信息请参考MultiDexApplication 

Limitations of the multidex support library

你应该意识到multidex support library有一些已知的限制,所以当你在将他合并到你的应用程序中时需要测试一下:

1..dex文件的安装在启动设备的数据分区很复杂,如果二级dex文件太大可能导致程序没有响应(ANR)。在这种情况下,您应与混淆器(ProGuard)应用代码缩减技术,减少.dex文件的大小和删除未使用的部分代码。

2.程序不能在在早已Android4.0(API level 14)之前的版本上使用multidex由于a Dalvik linearAlloc bug(Issue 22586)(http://b.android.com/22586)如果你使用API Level 14之前的版本,确保执行您的应用程序在启动时或者装载特定的类时,测试你的程序是否会出现问题。代码缩减可以消除这些潜在问题。

3.应用程序使用multidex配置会发出非常大的内存分配请求,这可能会导致运行时崩溃,由于a Dalvik linearAlloc bug(Issue 78035)(http://b.android.com/78035)。

4.Dalvik runtime执行时the primary dex文件可能需要复杂的请求。Android build tooling 更新处理Android需求,但是其他included libraries可能有额外的依赖需要,包括调用本地的java代码。一些library可能无法使用,直到multidex build tools更新后允许您指定必须包含在主dex文件的类。

Optimizing Multidex Development Builds

multidex配置需要显著增加构建处理时间,因为构建系统必须做出复杂决定,来确定哪些类必须包含在主dex文件以及哪些类可以包含在第二级dex文件中。这意味着常规构建执行与multidex作为开发过程的一部分,通常需要更长的时间,这可能减缓你的程序开发进度。

为了减少multidex输出构建时间,你应该创建两个变量来使用Android构建输出插件Gradle productFlavors: a development flavor and a production flavor。

a development flavor,设定一个最低21的SDK版本。这个设置生成multidex输出比使用ART-supported格式要快得多。the release flavor,设定一个最低SDK版本匹配你的项目最低支持版本。这个设置生成一个multidex APK,与更多的设备兼容,但需要更长的时间来构建。

以下构建配置示例演示了如何在Gradle构建文件设置这些 flavors :

android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
}
}
...
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}

完成了这个配置更改后,您可以使用与app的devDebug变量相结合的属性dev productFlavor和debug buildType。利用这个去创建一个minSdkVersion为Android API Level 21不使用proguard,启用multidex的debug app 。这些设置使Android gradle插件执行以下操作:

1.构建应用程序的每个模块(包括依赖库)作为单独的dex文件。这通常被称为pre-dexing。

2.包括每个dex文件没有修改APK文件

3.最重要的是,dex的模块文件不会被结合,所以可以避免来确定主dex文件内容的长时间运行的计算。

这些设置导致快速、增量构建,因为只有dex文件修改模块的会重新计算,重新包装成APK文件。这些设置构建APK只能用于测试Android 5.0及以上设备。然而,通过实现配置的flavors,你能够执行正常构建release-appropriate最低SDK和proguard设置

还可以建立其他变量,包括构建prodDebug变量,这需要更长的时间来构建,但可以用于测试外的开发。如果你从命令行执行gradle任务,您可以使用标准命令在结束的位置附加DevDebug(如./ gradlew installDevDebug)。

关于使用flavors与Gradle任务的更多信息,参考Gradle Plugin User Guide(http://tools.android.com/tech-docs/new-build-system/user-guide)

Tip您也可以提供一个自定义清单,或者为每个flavor自定义一个应用程序类,允许你在变量需要的时候使用MultiDexApplication应用程序类库或者调用 MultiDex.install()。

Using Build Variants in Android Studio

Build variants对管理multidex构建过程是非常有用的,Android Studio可以使用可视化操作来选择这些变量。

1.打开位于 left-sidebar的Build Variants 窗口(一般是在Android studio的左下)

2.点击Build Variants的名称来选择不同的变量,,如图1所示

Testing Multidex Apps

当multidex应用程序中使用instrumentation tests时,需要进行额外的配置。因为代码在multidex应用程序中不是位于单一DEX文件。所以instrumentation tests不能正常运行,除非程序为multidex配置。

为了使用instrumentation tests测试multidex app,需要配置MultiDexTestRunner。

下面build.gradle文件演示了如何配置来使用这个测试运行器:

android {
defaultConfig {
...
testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner"
}
}

     Note: With Android Plugin for Gradle versions lower than 1.1, you need to add the following dependency for multidex-instrumentation:

dependencies {
androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
exclude group: 'com.android.support', module: 'multidex'
}
}

你可以用instrumentation tests runner class直接或扩展它来适应您的测试需求。或者,您可以在现有的instrumentation中覆盖onCreate:

public void onCreate(Bundle arguments) {
MultiDex.install(getTargetContext());
super.onCreate(arguments);
...
}

     Note: Use of multidex for creating a test APK is not currently supported.

Building Apps with Over 65K Methods(解决APP引用方法总数超过65536)的更多相关文章

  1. 解决DATASNAP远程方法参数超过32个的问题

    群里有位同仁提出他有一个DATASNAP远程方法超过了32个参数,然后DELPHI编译通不过,提示方法参数不能超过32个,问怎么办?于是群内同仁纷纷出主意,我说用OLEVARINAT数组,有人说用RE ...

  2. 解决Android单个dex文件不能超过65536个方法问题

    当我们的项目代码过大时,编译运行时会报Unable to execute dex: method ID not in[0, 0xffff]: 65536)错误.当出现这个错误时说明你本身自己的工程代码 ...

  3. Android开发训练之第五章——Building Apps with Connectivity & the Cloud

    Building Apps with Connectivity & the Cloud These classes teach you how to connect your app to t ...

  4. android wear开发之:建立可穿戴设备的应用 - Building Apps for Wearables

    注:本文内容来自:https://developer.android.com/training/building-wearables.html 翻译水平有限,如有疏漏,欢迎批评指教. 译:山人 建立可 ...

  5. Android Studio2.3.3卡在Building 'xxx' Gradle project info的解决方法

    Android Studio版本:V2.3.3 操作系统环境:Ubuntu14.04  64bit 新安装好Android Studio后,在创建新的项目时或者在导入他人的项目代码时,Android ...

  6. SQLServer查看和解决死锁的方法

    http://luohonghong.blog.163.com/blog/static/78312058201142411533316/ SQLServer查看和解决死锁的方法 2011-05-24 ...

  7. django中跨app引用model

    可能是自己水平的原因,总感觉跨django中app引用有点怪怪的,所以在自己没有达到另一个级别之前就先把正确的解决 方案记一下吧. 一.django中跨app引用model,以app02中的model ...

  8. Flask-分开Models解决循环引用

    Flask-分开Models解决循环引用 在之前我们测试中,所有语句都在同一个文件中,但随着项目越来越大,管理起来有所不便,所以将Models分离.基本的文件结构如下 \—–app.py\—–mode ...

  9. 深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用(上)

    深入研究Block捕获外部变量和__block实现原理 前言 在上篇中,仔细分析了一下Block的实现原理以及__block捕获外部变量的原理.然而实际使用Block过程中,还是会遇到一些问题,比如R ...

随机推荐

  1. jQuery AJAX load() 方法

    jQuery load() 方法 jQuery load() 方法是简单但强大的 AJAX 方法. load() 方法从服务器加载数据,并把返回的数据放入被选元素中. 语法: $(selector). ...

  2. (转) c# ExecuteNonQuery() 返回值 -1

    这是之前我遇到问题,在网上找解决方法时找到的,当时复制到txt文档了,今天整理笔记又看到了,贴出来,便于以后查阅.原文的作者没记住~~ 查询某个表中是否有数据的时候,如果用ExecuteNonQuer ...

  3. gray code 格雷码 递归

    格雷码 the n-1 bit code, with 0 prepended to each word, followd by the n-1 bit code in reverse order, w ...

  4. 100. Same Tree(C++)

    100. Same Tree Given two binary trees, write a function to check if they are equal or not. Two binar ...

  5. ACM Sdut 2158 Hello World!(数学题,排序) (山东省ACM第一届省赛C题)

    题目描述 We know thatIvan gives Saya three problems to solve (Problem F), and this is the firstproblem. ...

  6. windows 安装maven 环境

    1.maven 下载地址: http://maven.apache.org/index.html 2.解压到目录并配置环境变量 M2_HOME   D:\maven\maven path       ...

  7. Ext.Date 方法

    1.Ext.Date.add(date,interval,value); 提供执行基本日期运算的简便方法; date 日期对象, interval 一个有效的日期间隔枚举值, value 向当前日期上 ...

  8. fedora22 无法联网的情况下rpm安装gcc5.1

    前天发生件很不幸的事.我在给ubuntu14.04安装NVIDIA显卡驱动的时候,想清空下一个目录,什么目录我也忘了,当时我正好切到root身份(平常我很少切root的),命令格式如下 rm -fr ...

  9. IS脚本学习

    OnFirstUIBefore:函数块用于第一安装应用时安装部件前所要完成的任务.一般在这里进行下列设: 1. 设置屏蔽 2. 显示欢迎信息,软件协议书或关于软件安装的其他说明信息 3. 从用户处获取 ...

  10. f.lux亮度自动改变

    笔记本在底光光镜下很刺眼,使用win7自带的亮度调节有的比较坑爹,我的Win+X里面没有亮度-! 使用f.lux可以自动根据时间调整光亮这一点很给力.   你,可以拥有.