一、基础知识补充:
为什么需要分包:
- Android2.3及以前版本用来执行dexopt(用于优化dex文件)的内存只分配了5M;
- 一个dex文件最多只支持65536个方法
1、dex分包:Android studio很方便的提供了MultiDex去解决dex分包
dex分包方案存在的问题:
- 由于第二个dex包是在Application的onCreate中动态注入的,如果dex包过大,会使app的启动速度变慢,因此,在dex分包过程中一定要注意,第二个dex包不宜过大。
- 由于上述第一点的限制,假如我们的app越来越臃肿和庞大,往往会采取dex分包方案和插件化方案配合使用,将一些非核心独立功能做成插件加载,核心功能再分包加载。(采用dex分包+插件化)
2、插件化:一些独立的功能做成一个单独的apk,当打开的时候使用DexClassLoader动态加载,然后使用反射机制来调用插件中的类和方法。
插件化方案存在的问题:
- 插件化只适合一些比较独立的模块;
- 必须通过反射机制去调用插件的类和方法,因此,必须搭配一套插件框架来配合使用;
二、什么是 HotFix?
1、当前背景
当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码,也要付出巨大的成本进行换包和重新发布。
2、热修复与插件化
叫法:热修复、热补丁、热更新、hotfix;
热修复:以补丁的方式动态修复紧急Bug,不再需要重新发布App,不再需要用户重新下载,覆盖安装(来自:安卓App热补丁动态修复技术介绍)
插件化:一个程序划分为不同的部分,以插件的形式加载到应用中去,本质上它使用的技术还是热修复技术,只是加入了更多工程实践,让它支持大规模的代码更新以及资源和SO包的更新。
①、正常开发流程
从流程来看,传统的开发流程存在很多弊端:
重新发布版本代价太大
用户下载安装成本太高
BUG修复不及时,用户体验太差
①、热修复开发流程
而热修复的开发流程显得更加灵活,优势很多:
无需重新发版,实时高效热修复
用户无感知修复,无需下载新的应用,代价小
修复成功率高,把损失降到最低
缺点:目前不是很稳定
三、几大流派
1、QQ空间超级补丁技术
超级补丁技术基于DEX分包方案,使用了多DEX加载的原理,大致的过程就是:把BUG方法修复以后,放到一个单独的DEX里,插入到dexElements数组的最前面,让虚拟机去加载修复完后的方法。
当patch.dex中包含Test.class时就会优先加载,在后续的DEX中遇到Test.class的话就会直接返回而不去加载,这样就达到了修复的目的。
但是有一个问题是,当两个调用关系的类不在同一个DEX时,就会产生异常报错。我们知道,在APK安装时,虚拟机需要将classes.dex优化成odex文件,然后才会执行。在这个过程中,会进行类的verify操作,如果调用关系的类都在同一个DEX中的话就会被打上CLASS_ISPREVERIFIED的标志,然后才会写入 odex 文件。
所以,为了可以正常的进行打补丁修复,必须避免类被打上CLASS_ISPREVERIFIED标志,具体的做法就是单独放一个类在另外DEX中,让其他类调用。
2、微信Tinker
微信针对QQ空间超级补丁技术的不足提出了一个提供DEX差量包,整体替换DEX的方案。主要的原理是与QQ空间超级补丁技术基本相同,区别在于不再将patch.dex增加到elements数组中,而是差量的方式给出patch.dex,然后将patch.dex与应用的classes.dex合并,然后整体替换掉旧的DEX,达到修复的目的。
3、AndFix实现原理
AndFix不同于QQ空间超级补丁技术和微信Tinker通过增加或替换整个DEX的方案,提供了一种运行时在Native修改Filed指针的方式,实现方法的替换,达到即时生效无需重启,对应用无性能消耗的目的。
原理图如下:
三者比对
四、阿里百川hotfix
阿里百川hotfix方案图解
基于阿里巴巴的andfix方案的一个扩展,对于andfix进行一些优化。它实提供了热修复的后台管理,注册阿里百川即可使用。
具体API可以参考阿里百川hotfix集成API 如有不明白的地方也可以问我,具体的实践demo就不贴地址。官网也有demo
阿里HotFix的使用中不被允许的情况
- 暂时不支持新增方法, 新增字段, 但是支持新增类, 所以需要新增方法/字段可以通过新增类来实现
- 不支持资源修复, so修复
- 三星note3,S4,S5的5.0设备以及X86设备不支持(点击查看具体支持的机型)
- 参数包括long,double,float基本类型的方法不能被patch, 不包括基本类型封装类Long,Double,Float
- 被反射调用的非静态方法不能被patch
- 参数超过8的方法不能被patch
- 构造方法不能被patch
- 使用注解的方法视情况而定是否支持被patch(详细说明参考Demo工程
BaseBug.md
文件中关于注解的说明) - 泛型参数的方法如果patch存在兼容性问题
- 在打包的时候偶尔会存在两次打包内部类的名字不一致问题,这种情况会导致打AndFix打包失败,暂时无解
- 我们建议不要通过GooglePlay发布带热修复SDK的APP,存在政策风险
- 暂不支持android7.0
违反上述规则, 则可能导致打补丁包或者加载补丁失败的情况, 代码实例请参考Demo工程下的BaseBug.md
文件下的详细说明, 另一方面这些限制随着SDK版本的升级会逐步的减少, 敬请期待.