配置方法数超过 64K 的应用(转)

参考自:developer.android.google.cn/studio/buil… 咱们在开发Androi应用的时候,有时会出现如下这种错html

//早期版本的构建程序会出现这个错
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
复制代码

java

//较新版本的 Android 构建系统虽然显示的错误不一样,但指示的是同一问题
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
复制代码

这些错误都会显示一个数字:65536。这个数子很重要,他表明的是单个Dalvik Executable(DEX)字节码文件内的代码可调用的引用总数。android

关于64K引用限制git

Android 应用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可执行字节码文件,其中包含用来运行您的应用的已编译代码。Dalvik Executable 规范将可在单个 DEX 文件内可引用的方法总数限制在 65,536,其中包括 Android 框架方法、库方法以及您本身代码中的方法。在计算机科学领域内,术语千(简称 K)表示 1024(或 2^10)。因为 65,536 等于 64 X 1024,所以这一限制也称为“64K 引用限制”。github

Android 5.0 以前版本的 Dalvik 可执行文件分包支持

Android 5.0(API 级别 21)以前的平台版本使用 Dalvik 运行时来执行应用代码。默认状况下,Dalvik 限制应用的每一个 APK 只能使用单个 classes.dex 字节码文件。要想绕过这一限制,您可使用 Dalvik 可执行文件分包支持库,它会成为您的应用主要 DEX 文件的一部分,而后管理对其余 DEX 文件及其所包含代码的访问。bash

Android 5.0 及更高版本的 Dalvik 可执行文件分包支持

Android 5.0(API 级别 21)及更高版本使用名为 ART 的运行时,后者原生支持从 APK 文件加载多个 DEX 文件。ART 在应用安装时执行预编译,扫描 classesN.dex 文件,并将它们编译成单个 .oat 文件,供 Android 设备执行。所以,若是您的 minSdkVersion 为 21 或更高值,则不须要 Dalvik 可执行文件分包支持库。 ART和Dalvik介绍app

规避64K限制框架

在将您的应用配置为支持使用 64K 或更多方法引用以前,您应该采起措施减小应用代码调用的引用总数,包括由您的应用代码或包含的库定义的方法。下列策略可帮助您避免达到 DEX 引用限制:ide

  • 检查您的应用的直接和传递依赖项 - 确保您在应用中使用任何庞大依赖库所带来的好处大于为应用添加大量代码所带来的弊端。一种常见的反面模式是,仅仅为了使用几个实用方法就在应用中加入很是庞大的库。减小您的应用代码依赖项每每可以帮助您规避 dex 引用限制。
  • 经过 ProGuard 移除未使用的代码 - 为您的版本构建启用代码压缩以运行 ProGuard。启用压缩可确保您交付的 APK 不含有未使用的代码。

使用这些技巧使您没必要在应用中启用 Dalvik 可执行文件分包,同时还会减少 APK 的整体大小。工具

配置您的应用进行 Dalvik 可执行文件分包

若是你的 MinSdkVersion大于等于 21,只须要在模块级build.gradle文件中将multiDexEnabled设置为true, 以下:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}
复制代码

若是MinSdkVersion小于 21,就比较麻烦了。 须按以下方式使用 Dalvik 可执行文件分包支持库

  • 修改模块级 build.gradle 文件以启用 Dalvik 可执行文件分包,并将 Dalvik 可执行文件分包库添加为依赖项,如此处所示:
android {
    defaultConfig {
        ...
        minSdkVersion 15 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.3'
}
复制代码
  • 根据是否要替换 Application 类,执行如下操做之一:

    • 若是您没有替换 Application 类,请编辑清单文件,按以下方式设置 <application> 标记中的 android:name

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapp">
          <application
                  android:name="android.support.multidex.MultiDexApplication" >
              ...
          </application>
        </manifest>
      复制代码
    • 若是您替换了 Application 类,请按以下方式对其进行更改以扩展 MultiDexApplication

      public class MyApplication extends MultiDexApplication { ... }
      复制代码
    • 或者,若是您替换了 Application 类,但没法更改基本类,则能够改成替换 attachBaseContext() 方法并调用 MultiDex.install(this) 来启用 Dalvik 可执行文件分包:

      public class MyApplication extends SomeOtherApplication {
            @Override
            protected void attachBaseContext(Context base) {
                 super.attachBaseContext(base);
                 MultiDex.install(this);
            }
      }
      复制代码

构建应用后,Android 构建工具会根据须要构建主 DEX 文件 (classes.dex) 和辅助 DEX 文件(classes2.dex 和 classes3.dex 等)。而后,构建系统会将全部 DEX 文件打包到您的 APK 中。

运行时,Dalvik 可执行文件分包 API 使用特殊的类加载器来搜索适用于您的方法的全部 DEX 文件(而不是仅在主 classes.dex 文件中搜索)。

Dalvik 可执行文件分包支持库的局限性

Dalvik 可执行文件分包支持库具备一些已知的局限性,将其归入您的应用构建配置之中时,您应该注意这些局限性并进行针对性的测试:

  • 启动期间在设备数据分区中安装 DEX 文件的过程至关复杂,若是辅助 DEX 文件较大,可能会致使应用无响应 (ANR) 错误。在此状况下,您应该经过 ProGuard 应用代码压缩以尽可能减少 DEX 文件的大小,并移除未使用的那部分代码。
  • 因为存在 Dalvik linearAlloc 错误(问题 22586),使用 Dalvik 可执行文件分包的应用可能没法在运行的平台版本早于 Android 4.0(API 级别 14)的设备上启动。若是您的目标 API 级别低于 14,请务必针对这些版本的平台进行测试,由于您的应用可能会在启动时或加载特定类群时出现问题。代码压缩能够减小甚至有可能消除这些潜在问题。
  • 因为存在 Dalvik linearAlloc 限制(问题 78035),所以,若是使用 Dalvik 可执行文件分包配置的应用发出很是庞大的内存分配请求,则可能会在运行期间发生崩溃。尽管 Android 4.0(API 级别 14)提升了分配限制,但在 Android 5.0(API 级别 21)以前的 Android 版本上,应用仍有可能遭遇这一限制。

声明主 DEX 文件中须要的类

为 Dalvik 可执行文件分包构建每一个 DEX 文件时,构建工具会执行复杂的决策制定来肯定主要 DEX 文件中须要的类,以便应用可以成功启动。若是启动期间须要的任何类未在主 DEX 文件中提供,那么您的应用将崩溃并出现错误 java.lang.NoClassDefFoundError

该状况不该出如今直接从应用代码访问的代码上,由于构建工具能识别这些代码路径,但可能在代码路径可见性较低(如使用的库具备复杂的依赖项)时出现。例如,若是代码使用自检机制或从原生代码调用 Java 方法,那么这些类可能不会被识别为主 DEX 文件中的必需项。

所以,若是您收到 java.lang.NoClassDefFoundError,则必须使用构建类型中的 multiDexKeepFile 或 multiDexKeepProguard 属性声明它们,以手动将这些其余类指定为主 DEX 文件中的必需项。若是类在 multiDexKeepFile 或 multiDexKeepProguard 文件中匹配,则该类会添加至主 DEX 文件。

multiDexKeepFile 属性

您在 multiDexKeepFile 中指定的文件应该每行包含一个类,而且采用 com/example/MyClass.class 的格式。例如,您能够建立一个名为 multidex-config.txt 的文件,以下所示:

com/example/MyClass.class
com/example/MyOtherClass.class
复制代码

而后,您能够按如下方式针对构建类型声明该文件:

android {
    buildTypes {
        release {
            multiDexKeepFile file('multidex-config.txt')
            ...
        }
    }
}
复制代码

请记住,Gradle 会读取相对于 build.gradle 文件的路径,所以若是 multidex-config.txt 与 build.gradle 文件在同一目录中,以上示例将有效。

multiDexKeepProguard 属性

multiDexKeepProguard 文件使用与 Proguard 相同的格式,而且支持整个 Proguard 语法。如需了解有关 Proguard 格式和语法的详细信息,请参阅 Proguard 手册中的 Keep Options 一节。

您在 multiDexKeepProguard 中指定的文件应该在任何有效的 ProGuard 语法中包含 -keep 选项。例如,-keep com.example.MyClass.class。您能够建立一个名为 multidex-config.pro 的文件,以下所示:

-keep class com.example.MyClass
-keep class com.example.MyClassToo
复制代码

若是您想要指定包中的全部类,你可使用-keep class com.example.** { *; }

而后,您能够按如下方式针对构建类型声明该文件:

android {
    buildTypes {
        release {
            multiDexKeepProguard('multidex-config.pro')
            ...
        }
    }
}
复制代码

优化开发构建中的 Dalvik 可执行文件分包

相关文章
相关标签/搜索