【Debug-AS】为方法数超过 64K(65536) 的应用启用多 dex 文件

目录

1. 编译报错

2. 解决方案

2.1 方法A:提高最低支持的SDK版本

2.2 方法B:启用多Dex文件支持

步骤1 修改module级别的build.gradle文件

步骤2 使用MultiDexApplication

2.3 方法C 规避64K限制

3. 原因分析:64K引用限制

3.1 Android 5.0 及更高版本的多 dex 文件支持

3.2 Android 5.0 之前版本的多 dex 文件支持


1. 编译报错

AGPBI: {"kind":"error","text":"Cannot fit requested classes in a single dex file (# methods: 121145 > 65536 ; # fields: 77718 > 65536)","sources":[{}],"tool":"D8"}
com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 
The number of method references in a .dex file cannot exceed 64K.
Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
	at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:131)
	...
    at com.android.tools.r8.D8.run(:11)
	at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:116)
	... 30 more
Caused by: com.android.tools.r8.utils.AbortException: Error: null, Cannot fit requested classes in a single dex file (# methods: 121145 > 65536 ; # fields: 77718 > 65536)
	at com.android.tools.r8.utils.Reporter.a(:21)
	at com.android.tools.r8.utils.Reporter.a(:7)
	at com.android.tools.r8.dex.VirtualFile.a(:33)
	at com.android.tools.r8.dex.VirtualFile$h.a(:5)
	at com.android.tools.r8.dex.ApplicationWriter.a(:13)
	at com.android.tools.r8.dex.ApplicationWriter.write(:35)
	at com.android.tools.r8.D8.d(:44)
	at com.android.tools.r8.D8.b(:1)
	at com.android.tools.r8.utils.t.a(:23)
	... 32 more

当您的应用及其引用的库超过 65536 种方法时,您会遇到一个编译错误,指明您的应用已达到 Android 编译架构规定的引用限制:

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

较低版本的编译系统会报告一个不同的错误,但指示的是同一问题:

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

这两种错误情况都会显示一个共同的数字:65536。此数字表示单个 Dalvik Executable (DEX) 字节码文件内的代码可调用的引用总数。

 

2. 解决方案

2.1 方法A:提高最低支持的SDK版本

适用于:minSdkVersion在21及其以上(Android 5.0及以上)

弊端:使支持的设备变少了,尤其是不支持万年钉子户Android4.4的厂商用户。

步骤:在module级别的build.gradle文件中,修改“minSdkVersion”的值为21及以上:

android {
    compileSdkVersion 29
    defaultConfig {
        minSdkVersion 21        // 21及以上
        ...
    }
}

 

2.2 方法B:启用多Dex文件支持

适用于:minSdkVersion在21以下用户(Android 5.0以下)

步骤1 修改module级别的build.gradle文件

①在 dependencies闭包 中添加 multiDex 的支持库
②在 defaultConfig闭包 中添加【multiDexEnable true

android {
        defaultConfig {
            ...
            minSdkVersion 15
            targetSdkVersion 29
            multiDexEnabled true        // 启用MultiDex
        }
        ...
}

dependencies {
        implementation 'androidx.multidex:multidex:2.0.1'        // 启用AndroidX的项目引用这个
        implementation 'com.android.support:multidex:1.0.3'      // 使用旧版Support库的项目使用这个
}

步骤2 使用MultiDexApplication

情景A:未自定义Application类

直接在AndroidManifest.xml配置清单文件中的<application>标签中的【android:name】引用MultiDexApplication

<?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" >    <!--使用MultiDexApplication-->
            ...
        </application>
    </manifest>

情景B:自定义Application类

可以让自定义的Application类所继承的父类从【Application】改为【MultiDexApplication】

public class MyApplication extends MultiDexApplication { ... }

情景C:自定义Application类但不方便更改基类

则可以改为替换 attachBaseContext() 方法并调用 MultiDex.install(this) 来启用多 dex 文件:

public class MyApplication extends MyBaseApplication {        // 基类保持不变
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);        // 启用MultiDex
      }
}

注意:在 MultiDex.install() 完成之前,不要通过反射或 JNI 执行 MultiDex.install() 或其他任何代码。MultiDex文件跟踪功能不会追踪这些调用,从而导致出现 ClassNotFoundException,或因 DEX 文件之间的类分区错误而导致验证错误

现在,当编译应用时,Android 编译工具会根据需要构造主要 DEX 文件(classes.dex) 和辅助 DEX 文件(classes2.dex...) 。然后,编译系统会将所有 DEX 文件打包到您的 APK 中。在运行时,多 dex 文件 API 使用特殊的类加载器来搜索适用于您的方法的所有 DEX 文件(而不是只在主classes.dex文件中搜索)。

MultiDex文件支持库具有一些已知的局限性,使用时应注意这些局限性并进行针对性的测试:

  • 启动期间在设备的数据分区上安装 DEX 文件的过程相当复杂,如果辅助 DEX 文件较大,可能会导致应用无响应 (ANR) 错误。为避免此问题,请启用代码压缩,以尽量减小 DEX 文件的大小,并移除未使用的代码部分。
  • 当运行的版本低于 Android 5.0(API 级别 21)时,使用MultiDex文件不足以避开 linearalloc 限制。此上限在 Android 4.0(API 级别 14)中有所提高,但这并未完全解决该问题。在低于 Android 4.0 的版本中,您可能会在达到 DEX 索引限制之前达到 linearalloc 限制。因此,如果您的目标 API 级别低于 14,请在这些版本的平台上进行全面测试,因为您的应用可能会在启动时或加载特定类组时出现问题。使用代码压缩可以减少甚至有可能消除这些问题。

 

2.3 方法C 规避64K限制

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

  • 检查应用的直接和传递依赖项 - 确保您在应用中使用任何庞大依赖库所带来的好处多于为应用添加大量代码所带来的弊端。一种常见的反面模式是,仅仅为了使用几个实用方法就在应用中加入非常庞大的库。减少您的应用代码依赖项往往能够帮助您规避 DEX 引用限制。
  • 通过 R8 移除未使用的代码 - 启用代码压缩以针对您的发布版本运行 R8。启用压缩可确保您交付的 APK 不含有未使用的代码。关于代码压缩,可访问:https://developer.android.com/studio/build/shrink-code.html

使用这些技巧使您不必在应用中启用多 dex 文件,同时还会减小 APK 的总体大小。

 

3. 原因分析:64K引用限制

Android 应用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可执行字节码文件,这些文件包含用来运行您的应用的已编译代码。Dalvik Executable 规范将可在单个 DEX 文件内引用的方法总数限制为 65,536,其中包括 Android 框架方法、库方法以及您自己的代码中的方法。

3.1 Android 5.0 及更高版本的多 dex 文件支持

Android 5.0(API 级别 21)及更高版本使用名为 ART 的运行时,它本身支持从 APK 文件加载多个 DEX 文件。ART 在应用安装时执行预编译,扫描 classesN.dex 文件,并将它们编译成单个 .oat 文件,供 Android 设备执行。因此,如果您的 minSdkVersion 为 21 或更高的值,则默认情况下启用多 dex 文件,并且您不需要多 dex 文件支持库

注意:使用 Android Studio 运行应用时,会针对您部署到的目标设备优化编译。这包括在目标设备运行 Android 5.0 及更高版本时启用多 dex 文件。由于此优化仅在使用 Android Studio 部署应用时应用,因此您可能仍需要为多 dex 文件配置发布版本,以规避 64K 限制。

3.2 Android 5.0 之前版本的多 dex 文件支持

Android 5.0(API 级别 21)之前的平台版本使用 Dalvik 运行时来执行应用代码。默认情况下,Dalvik 将应用限制为每个 APK 只能使用一个 classes.dex 字节码文件。要绕过这一限制,您可以在您的项目中添加多 dex 文件支持库,此库会成为应用的主要 DEX 文件的一部分,然后管理对其他 DEX 文件及其所包含代码的访问。具体参阅上述【2.2 方法B:启用多Dex文件支持】

 

参考文档:
https://developer.android.com/studio/build/multidex#mdex-gradle  # 为方法数超过 64K 的应用启用多 dex 文件 #

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值