1.官方文档

  https://developer.android.com/studio/build/multidex

主要内容:

  • 什么是64K限制
  • 编码时如何避免64K 限制
  • 拆分dex避免64K 限制

2.DEX

  DEX = Dalvik Executable , android Dalvik java 虚拟机的可执行字节码文件。APK文件包含 DEX,其中包含应用的已编译代码。

3.什么是64K限制

  Dalvik Executable 规定单个 DEX 文件内可引用的方法总数限制在 65,536,其中包括 Android 框架方法、库方法以及你自己的方法。

  在计算机科学领域内,术语千(简称 K)表示 1024(或 2^10)。65,536 等于 64 X 1024,因此这一限制也称为“64K 引用限制”。

  当android应用中方法数量超过这个65536,打包时报错信息如下:

  The number of method references in a .dex file cannot exceed 64K.

 如下图:

4.查看dex引用方法的数量

用android studio 分析一个apk,看下它的classes.dex 文件。

  • 这个apk内方法引用数已经达到限制,再添加一个方法、引用一个其它方法就会打包失败。
  • 其中红框65536是当前引用的方法数,同时也分析出了这个应用定义了个类,有个方法。

5.编码时避免64K 限制

  编码时应尽量减少应用代码中的方法数量。假如真的方法数量很多,常用避免64K限制策略如下:

5.1 减少依赖库

  减少代码依赖的库数量,能不用的就不用。确保在应用中引入庞大依赖库所带来的好处大于添加大量代码所带来的弊端。

5.2 启用代码压缩

通过 ProGuard 移除未使用的代码

 android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}

5.3 把函数放到本地so库中

在本地so库的的代码并不影响dex方法数量,假设f1()调用f2(),f3(),f4(),可以只把f1声明名native的,其它的放到so里。

下面是一个so库的源码文件,main.cpp ,里面有13w个函数,从fun_0() 到 fun_131071() ,并不影响dex.

 #include <jni.h>
#include <string> extern "C" JNIEXPORT void JNICALL
Java_com_example_dex64k_MainActivity_javaFun1(JNIEnv *env,jobject /* this */) {
std::string hello = "Hello from C++";
} void
Java_com_example_dex64k_MainActivity_javaFun2(JNIEnv *env,jobject){ }
void fun_0(){ printf("hello world %s,",__func__);}
void fun_1(){ printf("hello world %s,",__func__);}
void fun_2(){ printf("hello world %s,",__func__);}
void fun_3(){ printf("hello world %s,",__func__);}
void fun_4(){ printf("hello world %s,",__func__);}
void fun_5(){ printf("hello world %s,",__func__);}
void fun_6(){ printf("hello world %s,",__func__);}
void fun_7(){ printf("hello world %s,",__func__);}
void fun_8(){ printf("hello world %s,",__func__);}
void fun_9(){ printf("hello world %s,",__func__);}
void fun_10(){ printf("hello world %s,",__func__);} ...... void fun_131062(){ printf("hello world %s,",__func__);}
void fun_131063(){ printf("hello world %s,",__func__);}
void fun_131064(){ printf("hello world %s,",__func__);}
void fun_131065(){ printf("hello world %s,",__func__);}
void fun_131066(){ printf("hello world %s,",__func__);}
void fun_131067(){ printf("hello world %s,",__func__);}
void fun_131068(){ printf("hello world %s,",__func__);}
void fun_131069(){ printf("hello world %s,",__func__);}
void fun_131070(){ printf("hello world %s,",__func__);}
void fun_131071(){ printf("hello world %s,",__func__);}

6.拆分dex避免64K 限制

  把apk的dex拆分成多个,可以避免64K 限制。

6.1 api >= 21 时如何拆分dex

  在模块的 build.gradle 文件中将  multiDexEnabled 设置为 true,如下:

 apply plugin: 'com.android.application'

 android {
compileSdkVersion 29
buildToolsVersion "29.0.1"
defaultConfig {
applicationId "com.example.dex64k"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//...
}
buildTypes {
release {
minifyEnabled false
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
//...
} dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:multidex:1.0.3'
//...
}

6.2 api < 21 时如何拆分dex

  • 打开 multiDexEnabled
  • 添加 com.android.support:multidex:1.0.3 依赖
 android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 28
multiDexEnabled true
}
...
} dependencies {
implementation 'com.android.support:multidex:1.0.3'
}

apk内dex文件如下:

6.3 拆分完dex后要设置application

A.未自定义application类时

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.dex64k"> <application
android:name="androidx.multidex.MultiDexApplication"
>
...
</application> </manifest>

如果用的不是androidx,那么

    android:name="android.support.multidex.MultiDexApplication"

B.自定义了Application时

那么它的基类应该是 MultiDexApplication

 import androidx.multidex.MultiDexApplication;

 public class Dex64App extends MultiDexApplication {

 }

如果无法修改Application的基类,那么

 import android.app.Application;
import android.content.Context;
import androidx.multidex.MultiDex; public class Dex64App extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

7.拆分dex的缺点

Dalvik 可执行文件分包支持库具有一些已知的缺点.

  • 启动期间在设备数据分区中安装 DEX 文件的过程相当复杂,如果DEX 文件较大,可能会导致ANR错误.
  • 在api < 14 的设备上可能无法启动,也可能产生各种错误。            (http://b.android.com/22586)
  • 应用发出非常庞大的内存分配请求,则可能会在运行期间发生崩溃。(http://b.android.com/78035

8.指定某些类到主dex中

  如果启动期间需要的类未在主 DEX 文件中找到,应用将崩溃并出现错误 java.lang.NoClassDefFoundError。

  使用 multiDexKeepFile 或 multiDexKeepFile 可以手动将某些类指定在主 DEX 文件中。

8.1 multiDexKeepProguard

  multiDexKeepProguard 文件使用与 Proguard 相同,并且支持全部 Proguard 语法。

 apply plugin: 'com.android.application'

 android {
...
buildTypes {
release {
minifyEnabled true
multiDexEnabled true
multiDexKeepProguard file('multidex-config.pro')
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
...
}

  multidex-config.pro与Module下的build.gradle同级,它内容如下:

 -keep class com.example.dex64k.Dex64App
-keep class com.example.dex64k.MainActivity
-keep class com.example.dex64k.dex1
-keep class com.example.dex64k.dex2 #-keep class com.example.** { *; } // All classes in the com.example package

8.2 注意事项

  • 要打开混淆选项
  • 官网示例中的 multiDexKeepProguard('multidex-config.pro') 要改成  multiDexKeepProguard file('multidex-config.pro')

8.3  multiDexKeepFile

 1 android {
2 compileSdkVersion 29
3 buildToolsVersion "29.0.1"
4 ...
5 buildTypes {
6 release {
7 minifyEnabled true
8 multiDexEnabled true
9 multiDexKeepFile file('multidex-config.txt')
10 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
11 }
12 }
13 compileOptions {
14 //...
15 }

  其中 multidex-config.txt 文件与Module下的build.gradle同级,它内容如下:

1 com/example/dex64k/Dex64App.class
2 com/example/dex64k/MainActivity.class
3 com/example/dex64k/dex1.class

关于dex 64K 引用限制的更多相关文章

  1. [转]預防 Android Dex 64k Method Size Limit

    转载自:http://ingramchen.io/blog/2014/09/prevention-of-android-dex-64k-method-size-limit.html 08 Septem ...

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

    关于方法数超限,Google官方给出的方案是这样的:https://developer.android.com/intl/zh-cn/tools/building/multidex.html 我也写过 ...

  3. 配置方法数超过 64K 的应用

    随着 Android 平台的持续成长,Android 应用的大小也在增加.当您的应用及其引用的库达到特定大小时,您会遇到构建错误,指明您的应用已达到 Android 应用构建架构的极限.早期版本的构建 ...

  4. dex文件格式三

    先来看看整体的结构,结构体定义在DexFile.h里面   在dexFileSetupBasicPointers中设置各个子结构体,当然是在解析DexHeader之后 源码在DexFile.c文件中 ...

  5. 【转】Android studio 解决64K超出链接数限制问题

    http://my.oschina.net/gabriel1215/blog/602608 目录[-] 使用MultiDex支持库 注意事项 结论 如果你是一个android开发者,你至少听说过的Da ...

  6. Android学习笔记----解决“com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536”问题

    同时在工程中引入了多个第三方jar包,导致调用的方法数超过了android设定的65536个(DEX 64K problem),进而导致dex无法生成,也就无法生成APK文件. 解决办法如下: 1.谷 ...

  7. 解决“com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536”问题(l转)

    同时在工程中引入了多个第三方jar包,导致调用的方法数超过了android设定的65536个(DEX 64K problem),进而导致dex无法生成,也就无法生成APK文件. 解决办法如下: 1.谷 ...

  8. Android安全–Dex文件格式详解

    Dex文件是手机上类似Windows上的EXE文件,dex文件是可以直接在Dalvik虚拟机中加载运行的文件. 首先我们来生成一个Dex文件. 新建文件Hello.java内容如下: class He ...

  9. 解决android studio上“com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65935”问题

    我是在更换应用的一个jar包时发生的这个错误,网上查到说是因为同时在工程中引入了多个第三方jar包,导致调用的方法数超过了android设定的65935个(DEX 64K problem),进而导致d ...

随机推荐

  1. cmd以管理员打开

  2. Python全栈开发:进程代码实例

    进程与线程的关系 #!/usr/bin/env python # -*- coding;utf-8 -*- """ 多进程(主进程,子进程): 优点:能同时利用多个CPU ...

  3. 19-10-27-S

    作者太巨辣! %%%乔猫 好. ZJ一下: 哭笑不得. T1直接审错题(没发现题目里那个憨P的更新限制),然后直接跑了$\mathsf{SPFA}$,然后我又发现了.以为我死了,结果手玩一下发现……那 ...

  4. 基于知识图谱的APT组织追踪治理

    高级持续性威胁(APT)正日益成为针对政府和企业重要资产的不可忽视的网络空间重大威胁.由于APT攻击往往具有明确的攻击意图,并且其攻击手段具备极高的隐蔽性和潜伏性,传统的网络检测手段通常无法有效对其进 ...

  5. Windows Server 2008 R2 部署服务

    Windows Server 2008 R2 部署服务 部分参考: Windows Server 2008 R2 部署服务 - 马睿的技术博客 - 51CTO技术博客http://marui.blog ...

  6. 安装 adb centos 7

    打开 https://centos.pkgs.org/7/epel-x86_64/android-tools-20130123git98d0789-5.el7.x86_64.rpm.html 下载 r ...

  7. 2018CCPC吉林赛区 | 部分题解 (HDU6555 HDU6556 HDU6559 HDU6561)

    // 杭电上的重现赛:http://acm.hdu.edu.cn/contests/contest_show.php?cid=867 // 杭电6555~6566可交题 A - The Fool 题目 ...

  8. css3 做border = 0.5px的细线

    参考: https://blog.csdn.net/Tyro_java/article/details/52013531

  9. 2018-10-19-C#-序列类为-xml-可以使用的特性大全

    title author date CreateTime categories C# 序列类为 xml 可以使用的特性大全 lindexi 2018-10-19 9:9:47 +0800 2018-6 ...

  10. git的三个区域比较

    工作区: 暂存区: 提交区: 工作区与暂存区比较:git diff 工作区与提交区比较:git diff 提交hash码或者HEAD 暂存区与提交区比较:git diff --cached 两个不同提 ...