Android进阶指南
65535 问题(64K 问题)
出现这个问题的根本原因是在 DVM 源码中的 MemberIdsSection.java 类中,有如下一段代码:
如果 items 个数超过 DexFormat.MAX_MEMBER_IDX 则会报错,DexFormat.MAX_MEMBER_IDX 的值为 65535,items 代表 dex 文件中的方法个数、属性个数、以及类的个数。也就是说理论上不止方法数,我们在 java 文件中声明的变量,或者创建的类个数如果也超过 65535 个,同样会编译失败,Android 提供了 MultiDex 来解决这个问题。很多网上的文章说 65535 问题是因为解析 dex 文件到数据结构 DexFile 时,使用了 short 来存储方法的个数,其实这种说法是错误的!
解决:MultiDex
Multidex 分包技术
1、分包的原因?
64K 的问题,dex 的 items 超过了 DexFormat.MAX_MEMBER_IDX 即 65535 限制(items 代表有方法个数、属性个数、类的个数等)
2、解决
用 multidex
3、MultiDex 实现原理
- MultiDex 工作流程分为 2 个部分,一个部分是打包构建 apk 的时候,将 dex 文件拆分若干个小的 dex 文件
- 另外一个部分是在启动 apk 的时候,同时加载多个 dex 文件(具体是加载 Dex 文件优化后的 odex 文件,不过文件名还是.dex),这一部分工作从 Android5.0 开始系统已经帮我们做了,但是 Android5.0 之前还是需要通过 MultiDex 库来支持。
4、Multidex 的局限性
- Application Not Responding 如果第二个(或其他个)dex 文件很大的话,安装.dex 文件到 data 分区时可能会导致 ANR(应用程序无响应),此时应该使用 ProGuard 减小 DEX 文件的大小
- 由于 Dalvik linearAlloc 的 bug 的关系,使用了 multidex 的应用可能无法在 Android 4.0 (API level 14) 或之前版本的设备上运行
如何手动分包?
插件化和热修复
热修复
热修复原理
1、ARTMethod
AndFix
2、dex 替换
Nuwa,Tinker
3、InstantRun
代表就是美团的 Robust
Tinker 原理
- 使用 DexClassLoader 加载补丁包的 dex 文件
- 通过反射获取 DexClassLoader 类的 pathList(DexPathList),再次通过反射获得 dexElements 数组。
- 获取加载应用类的 PathClassLoader,同样通过反射获取它的 dexElements 数组。
- 合并两个 dexElements 数组,且将补丁包的 dex 文件放在前面。
根据类加载机制,一个类只会被加载一次,DexPathList.findClass 方法中是顺序遍历数组,所以将补丁的 dex 文件放在前面,这样 bug 修复类会被优先加载,而原来的 bug 类不会被加载,达到了替换 bug 类的功能(补丁包中的修复类名、包名要和 bug 类相同)
- 再次通过反射将合并后的 dexElements 数组赋值给 PathClassLoader.dexElements 属性。
插件化
1、占坑式原理
- 占坑 Activity
- hook Instrumention
- 替换占坑 Activity
插件化和热修复对比
插件化和热修复的原理,都是动态加载 dex/apk 中的类/资源,两者的目的不同。插件化目标在于加载 activity 等组件,达到动态下发组件的功能,热修复目标在修复已有的问题。目标不同,也就导致其实现方式上的差别。由于目标是动态加载组件,所以插件化重在解决组件的生命周期,以及资源的问题。而热修复重在解决替换已有的有问题的类/方法/资源等。