Android 多Dex分包机制

2023-05-16

问题引入

随着项目工程越来越庞大,代码的方法数不断增长到一定程度,就出现Android 低版本系统应用无法安装的情况。那么这是哪里出错了?Android系统对安装包有哪些限制?
前一阵子,我们发现公司的某一个业务,在Android 2.3及系统安装不了。此时,我们该业务的Android客户端开发已经有50个人。一般外面公司的Android开发也就2~3个,代码的体量也很难增长到像我们这样的规模。但任何一个大项目都会碰到该问题。
我们来看一下,出现问题时,开发工具会有如下的提示:

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

或是

trouble writing output: Too many field references:131000; max is65536.
You may tryusing–multi-dex option.

上述两个错误提示不一样,但问题都是同一个问题。只是开发工具的编译系统版本不同,提示不同。可以看出,是某一项达到系统规定的阀值,导致安装失败了。
问题定位
从上述的提示来看,里面有一个数字65536很抢眼,这个正好是Java int的最大值。由于Android代码是以dex形式的存在,那么dex在系统里是如何定义的呢?

首先,每一个Dex文件,都会有这么一个头部信息DexHeader:
从上面可以看出,在头部信息里面分别定义了filed(字段)、method(方法)、classDefs(类)等的数量,这个数量是u4类型。至于u4类型的定义是

可以从上面的定义看出,u4类型就是uint32_t,而uint32_t正好是无符号整型2^32=65536。因此,这也就不难解释,为什么dex文件超过这个限制后,就出现无法安装的情况。

一般情况下,dex的方法数最多,因此很容易达到65536这个数量限制,而字段和类则比较难。所以,出现问题的都是方法超出居多。

Dex引用构成

一个Dex文件,它的引用组要由下面三部分组成。
因此,dex引用的方法数不仅仅和自己编写的代码有关,还和引用系统的方法数、第三方集成库的方法数有关。因此,方法数超标,也是多方面的原因构成的。
想看自己dex文件的方法数,可以搜索dex-method-counts获得自己dex数量。

解决思路

从上面的分析可以看出,出问题的原因是因为单个Dex引用的方法数超标了。那么我们是否可以拆分多个dex,从而避免单个dex的方法数超标?答案当然是可以的。
目前,为了解决dex方法数超标的问题,有三种主流思路:代码瘦身、插件化和分dex。这三种解决方案可以结合使用,效果更好。

代码瘦身

代码瘦身,可以从自己定义/引用的方法和第三方引入的库下手。

通过review自己的代码,减少方法数的定义(去掉一行函数,比如get和set,一般都是一行的,可以直接对变量做引用)、合并方法、减少对外部的依赖,从而减少最终dex引用的限制。

第三方引用库,一般一个引用jar包里面,有很多方法其实我们是引用不到的,我们可以对这些jar包做瘦身(jar是压缩包,里面都是class文件,我们去掉一些不相关的class,从而减少jar包大小),从而减少最终dex的引用限制。

同时,可以引入Proguard工具,开启Proguard的代码瘦身功能,会自动帮你删除无用的代码,最终生成的dex文件也会变小的。

插件化

插件化,也就是对程序中独立的模块做成插件,从而减少主dex文件的大小。插件化的思路其实就是对dex做拆分,从而使主dex变得更小,插件则是以独立的dex存在。

但插件化需要自己开发一套插件化的框架,成本较高,而且只有独立的模块才适合做插件。很多时候,我们的代码存在很多引用,很难拆成独立的模块。

因此,插件化,是无法从根本上解决这个问题。

分Dex

上述方案都不能从根本上解决问题,可以采用分dex的方案,适用范围更广。

分dex是将dex分成多个dex,从而避免单个dex的引用超过限制,分dex的方案不需要关心独立性问题,而且Android Studio开发工具已经支持这项能力,使用起来,成本也很低。

分Dex实现

Gradle的Android插件,从SDK build tools 21.1或是更高的版本就支持多dex的能力,需要自己手动配置一下。步骤如下:

5.1开启分包功能
在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'
}      

2修改Application入口

一种方案是,直接修改AndroidManifest,使用MultiDexApplication,如下所示:

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

另一种方案, 如果自己有自定义的Application,则可以重写attachBaseContext()方法,在里面调用MultiDex.install(this) 来开启分dex功能。

当所有的配置OK后,Android编译工具会自动生成一个主dex(classes.dex),和其它附属dex(classes2.dex,classes3.dex)。当然这个附属dex是根据需要来会生成。

分Dex局限性

虽然分Dex,可以解决dex方法数限制问题,但开发必须关注以下问题:

  • 1附属包过大

    附属包如果过大,可能导致应用启动时发生ANR。所以,需要使用Proguard来做代码瘦身,减少附属包的大小。

  • 2低版本运行问题

    在Android 4.0以下(API level 14以下),可能出现运行不起来的问题,原因是Dalvik linearAlloc的bug。同样通过proguard可以瘦身代码,避免这个问题。

  • 3内存消耗问题

    使用多dex方案,会导致应用请求更多的内存空间,从而出现crash。原因同样来自Dalvik的linearAlloc的内存分配限制。虽然在Android 4.0上已经提高了内存分配限制,但仍然还是很有可能达到这个限制。

  • 4代码分包的复杂性
    虽然,分包解决了dex引用限制的问题,但是由于dex内部复杂的引用,所以,在对代码分包时,必须考虑到启动时就需要用到的,都必须放到主dex中。

目前编译开发工具还不支持指定class必须放到主dex中,后续开发工具会逐步完善并支持该功能。当然,如果你觉得有必要控制哪些代码必须在主dex里面,可以自己编写编译脚本。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 多Dex分包机制 的相关文章

  • C++中enum与字符串或CString互相转换的方法

    C 43 43 中没有专门为enum与字符串或CString互相转换的直接方法 xff0c 但是工作中会常遇到相互转换的场景 下面介绍一种自己实现的方法 xff0c 首先得定义一个enum类型 xff0c 同时 xff0c 定义一个与之对应
  • VC++标准化路径PathCanonicalize

    外部输入的参数不能直接作为文件路径 xff0c 防止被恶意攻击 xff0c 比如构造一个跨目录限制的文件路径 etc passwd或 boot ini xff0c 或构造一个指向系统关键文件的链接文件symlink 34 etc shado
  • 解决时间机器无法识别硬盘问题

    T7 SSD分区后做时光机器 xff0c 但无法识别 xff08 如图 xff09 xff0c 问题解决 一 问题描述 xff1a 当时没保存照片 xff0c 图片来自网络 问题详情 xff1a 硬盘没分区且是苹果可识别的格式 xff08
  • vscode stm32cubemx 优雅开发stm32,最简单步骤教程

    配置安装环境 下载STM32cubeMX xff0c 这个大家可以自己在stm的官网下载到下载VSCode下载arm none eabi gcc下载MinGW w64 xff0c 为了实现里面的makefile 等功能下载OpenOCD这里
  • Epoll两种模式浅析(ET or LT)

    linux异步IO浅析 http hi baidu com kouu blog item e225f67b337841f42f73b341 html epoll有两种模式 Edge Triggered 简称ET 和 Level Trigge
  • 5GC自学-5G接入网组成

    5GC接入网 如图所示 xff1a EPC xff08 就是4G核心网 xff09 被分为New Core xff08 5GC xff0c 5G核心网 xff09 和MEC xff08 移动网络边界计算平台 xff09 两部分 MEC移动到
  • 《C++程序设计实验3》

    描述 晶晶的朋友贝贝约晶晶下周一起去看展览 xff0c 但晶晶每周的1 3 5必须上课 xff0c 请帮晶晶判断她能否接受贝贝的邀请 xff0c 如果能输出YES xff1b 如果不能则输出NO 输入 输入贝贝邀请晶晶去看展览的日期 xff
  • webpack--PWA(网站离线访问技术)

    webpack config js const WorkboxWebpackPlugin 61 require 39 workbox webpack plugin 39 终端下载npm i workbox webpack plugin D
  • Ubuntu安装wine的方法(Linux Ubuntu安装Windows软件)

    我打算完全从头开始 xff0c 写一个专门用于桌面办公的纯国产操作系统 xff0c 规避主流操作系统上影响用户体验的问题 xff0c 系统力求简洁 前言 xff1a wine可以让你在linux上运行一些常用的windows xff0c 如
  • 冒泡排序,并输出每一趟的排序结果

    span class token keyword public span span class token keyword static span span class token keyword void span span class
  • [Linux]基于select的Socket编程实现客户端群聊[非阻塞]

    先看效果 xff1a 客户端的代码 xff1a span class hljs comment Create by Gpwner 2017年1月5日21 30 16 span span class hljs preprocessor inc
  • 深入理解Nginx~用于调试进程和定位问题

    1 是否以守护进程方式运行Nginx 语法 xff1a daemon on off 默认 xff1a daemon on 守护进程 xff08 daemon xff09 是脱离终端并且在后台运行的进程 它脱离终端是为了避免进程执行过程中的信
  • 笔记本电脑坏了,那些零件可以再利用

    1 买个硬盘盒 xff0c 把笔记本硬盘改装成移动硬盘 2 把笔记本的屏幕拆下来 xff0c 上淘宝买改装用的套装 xff0c 可以把笔记本的屏幕改装成扩展显示器和电视 xff08 重点推荐 xff09 3 内存条拆下来 xff0c 留着以
  • 天气预报API接口大全

    国家气象局提供的天气预报接口 接口地址 xff1a http www weather com cn data sk 101010100 html http www weather com cn data cityinfo 101010100
  • VMware安装Debian完成,启动出现黑屏现象,仅有一个光标,以及给出解决办法

    VMware安装Debian完成 xff0c 启动出现黑屏现象 xff0c 仅有一个光标 xff0c 以及给出解决办法 一 启动黑屏问题二 解决办法 一 启动黑屏问题 VMware安装Debian过程中 xff0c 一路选择默认选项 xff
  • C语言对栈的操作

    span class hljs preprocessor include lt stdio h gt span span class hljs preprocessor include lt stdlib h gt span span cl
  • Godot实用代码1000例

    关于 这是 Godot实用代码1000例 的CSDN博客版本 xff08 之前是PPT版本 xff09 xff0c 将收录笔者自己探索和学习的一些简单Godot编程案例 文章目录 关于原版开篇的废话适合哪些人群建议前置知识 基础的移动 旋转
  • Godot官网新闻翻译 - 2015年

    本文是 Godot官网新闻翻译 系列的第1篇 xff0c 该系列旨在翻译和汇总Godot官网所发布的所有新闻 让更多英文不好的童鞋可以领悟官方新闻中的重要信息和真谛 官网新闻地址 xff1a https godotengine org ne
  • 一文简单了解并构建DockerFile

    GreatSQL社区原创内容未经授权不得随意使用 xff0c 转载请联系小编并注明来源 GreatSQL是MySQL的国产分支版本 xff0c 使用上与MySQL一致 作者 xff1a 蟹黄瓜子文章来源 xff1a GreatSQL社区投稿
  • 更新sudo apt source提示sources.list拼写错误的解决方法

    如果sudo apt uodate 更新失败 xff0c 多半是源的问题 xff0c 这是轻的症状 xff0c 根据提示 xff0c 把产生错误错误源去掉就行了 xff0c 但是情况较复杂怎么办 xff1f 如果有一天 xff0c 你在终端

随机推荐

  • 静态库和动态链接库的安装(Windows环境)

    库的安装 xff1a freeglut为例 1 在SourceForge下载freeglut库 xff0c 其中包括include src文件夹和CMakesLists txt freeglut download SourceForge n
  • C++ share_ptr 循环引用问题浅析

    share ptr指针涉及到循环引用问题会因为share ptr指针对应的use count 无法清0 xff0c 导致内存泄露 xff0c 直接上例子 xff1a class S B class S A public shared ptr
  • 树莓派raspberry pi更换国内镜像

    有时候使用sudo apt get 和pip install 安装软件和一些库的时候下载速度简直是龟速如下图 xff1a xff0c 是因为在系统默认状态下 xff0c 安装软件会选择从国外的服务器上下载软件 默认地址是http raspb
  • 将SQL Server的任意记录转换为JSON格式(JQGRID) -- 支持SQL 2005

    从SQL 2008开始 xff0c SQL Sever已经支持JSON数据 xff0c SQL 2016已经对JSON数据的处理支持非常完善 对于SQL 2016以上版本的用户 xff0c 可以直接调用原生方法 xff0c 效率更高 因客户
  • gradle安装

    Gradle是一个主要用于Java项目的通用构建工具 它结合了Ant和Maven的最佳功能 与使用XML进行脚本编写的前辈不同 xff0c Gradle使用Groovy xff0c 这是一种动态的 xff0c 面向对象的Java平台编程语言
  • 树列表控件CTreeListCtrl类

    翻译来源 xff1a https www codeproject com Articles 2913 A Tree List Control 作者 xff1a TigerX 下载源文件 102 Kb 下载演示文件 54 6 Kb 介绍 这是
  • 2019xupt-acm校赛 题解(C.给你一个666)by出题组tongtong

    重现赛链接 2019 ACM ICPC Xi 39 an University of Posts amp Telecommunications School Contest 前面的话 有幸参与2019XUPT ACM校赛出题和裁判工作 过程
  • 【安装】在Windows下安装Debian(双系统)

    安装 一 前期准备二 Rufus制作启动盘三 修改BIOS四 以U盘启动安装Debian五 设置分区 一 前期准备 1 一个至少8G的U盘 2 U盘引导制作工具 我用的Rufus 链接 3 Debian的iso镜像 我用的清华镜像 点进链接
  • Swift 四种实现单例的方式

    单例模式 单例模式是设计模式中最简单的一种 xff0c 甚至有些模式大师都不称其为模式 xff0c 称其为一种实现技巧 xff0c 因为设计模式讲究对象之间的关系的抽象 xff0c 而单例模式只有自己一个对象 当你只需要一个实例的时候需要使
  • python之字符串切片为列表

    函数名说明A replace old new count 将字符串A里的old替换为new xff0c 替换次数为counta join A 将字符串序列A之间插入字符aA split sep xff0c count 将字符串A切片输出为列
  • 用python实现最简单简单的计算器

    直接上代码 xff1a 密码是123 过程 体验 收获及自我评价 xff0c 本人在活动的具体工作可以输入1000字 import os 让解释器停住 xff0c 引用os模块 print 34 欢迎使用计算程序 34 print 34 请
  • Android 一键分享功能

    之前在做项目时遇到这么个需求 xff0c 就是用户点击Menu或者一个按钮可以把文字分享到各大微博例如新浪微博 腾讯 人人 开心 校内等 现在我给大家演示一下 xff08 一 xff09 先建一个工程文件ShareDemo xff08 二
  • android listview单击事件

    今天我们来学习下listview 单击事件 xff0c 这在开发中是经常用的组件之一 1 新建一个项目 xff0c 名为ListViewDemo 2 布置布局文件main xml lt xml version 61 34 1 0 34 en
  • android 焦点事件

    今天介绍下android中的焦点事件 xff0c 之前在项目有用到过 这块不是很难 xff0c 大家跟着过一遍吧 xff0c 用到的时候直接把我下面这段代码拷贝过去就ok了 1 建一个工程 xff0c 名为TestFocus 2 在布局文件
  • android 绘图、自定义组件

    我们在开发当中很多时候都需要自定义组件 xff0c 通过自定义组件 xff0c 可以随心所欲定制酷炫的效果 下面将演示自定义绘图组件 我们要绘制一个红色的线条 1 建立工程文件 xff0c 名为TouchDemo 2 布局文件 lt xml
  • SVN常用命令详解

    命令的使用 1 检出 svn co http 路径 目录或文件的全路径 本地目录全路径 username 用户名 password 密码svn co svn 路径 目录或文件的全路径 本地目录全路径 username用户名 password
  • androidstudio 拆包时设置dex方法个数

    前言 Android应用程序 xff0c 最终发布成一个apk xff0c 安装到手机上 apk文件随便用一个解压缩文件打开 xff0c 可以看到里面有一个classes dex文件 xff0c 这就是之前工程中所有的代码 xff0c 以及
  • hash算法原理详解

    散列表 它是基于快速存取的角度设计的 xff0c 也是一种典型的 空间换时间 的做法 顾名思义 xff0c 该数据结构可以理解为一个线性表 xff0c 但是其中的元素不是紧密排列的 xff0c 而是可能存在空隙 散列表 xff08 Hash
  • Android Studio 打包时 Signature Version 选择 V1 V2 说明

    问题描述 v1和v2 Android 7 0中引入了APK Signature Scheme v2 xff0c v1是jar Signature来自JDK V1 xff1a 应该是通过ZIP条目进行验证 xff0c 这样APK 签署后可进行
  • Android 多Dex分包机制

    问题引入 随着项目工程越来越庞大 xff0c 代码的方法数不断增长到一定程度 xff0c 就出现Android 低版本系统应用无法安装的情况 那么这是哪里出错了 xff1f Android系统对安装包有哪些限制 xff1f 前一阵子 xff