android 热修复 & 插件化学习
什么是热部署?
热部署指在App运行时,加载外部的代码或者资源,实现对自身代码或者资源的覆盖、替换,在避免重新安装应用的情况下,实现Bug修复或者应用功能扩展,也就是热修复和插件化开发。
热部署的本质需求和语言支持
我们知道C或者C++语言允许我们使用头文件来引用外部定义,在运行时进行动态的库加载。这么设计的目的,是为了满足程序动态扩展的需求,使得大型的程序可以分部实现、维护、存储,提高程序的扩展性和复用性。在这里,头文件的存在,是为了生成符号引用,解决编译时的编译依赖和查找运行时的调用函数。
那么在java语言里也有同样的需求和机制。我们知道java是完全的面向对象语言,所有的执行逻辑由类负责实现。为了支持程序的动态扩展能力,Java提供了两种机制:
- 多态。允许父类引用,指向子类实现。这样我们可以在编译时依赖接口或父类,运行时使用具体类型或子类型,完成动态扩展。
- 反射。允许我们以外部视角,指定具体的类、方法、属性等进行加载和使用。
在第一种机制中,父类和接口就相当于C/C++的头文件,用于向依赖程序提供类型信息,然后通过反射机制完成父子类型的衔接,实现动态扩展。而实现这俩能力,都是由ClassLoader的设计机制来实现的。
为了在运行时能够找到子类型,ClassLoader提供了根据指定类型信息和加载路径,动态地将字节码文件加载到内存作为类来使用。当然,为了程序的完整和安全,它还会对字节码进行规范和安全检查。ClassLoader的设计和实现,是java动态扩展全部的能力和限制所在。
热部署的平台特性
Android应用与Java程序在结构、安装、启动方式上有着较大的区别。Android应用运行于移动平台,有着固定的应用打包、安装、校验流程,同时Android应用不再由Java的类加载器结构直接加载类来运行,而是由框架实现类Instrumentation,根据应用清单,使用定制化的各种Dex加载器加载对应的组件来运行。所以,要在Android平台上实现程序的动态扩展,一方面要遵循平台的架构规范,同时要绕开它的限制,才能正确地加载我们需要的代码和资源。
总体来说,要深入理解插件升级的原理,必须要理解jvm的启动过程, java类加载和使用过程,android framework的启动过程,app的启动过程。 插件升级的本质,就是在这些过程中,根据我们的需求修改原有的逻辑,来实现动态加载效果。
要理解上述的这些过程,更深层次地,要理解jvm产生的背景,要解决的问题,以及选择的策略(设计)。同时要理解android使用java作为应用开发语言,并为此搭建的框架的动机,要解决哪些问题,以及选择的策略(设计)。
明确基本需求
- 修复已知Android组件、自定义类的Bug
- 修复、替换资源,实现换肤等效果
- 插件化开发,动态扩展功能模块
开源框架
热部署的基本原理有两种,一种是ClassLoader原理,一种是Native替换方案。热部署的成熟开源框架有,DroidPlugin,Small,Altas,RePlugin,Tinker,AndFix,Sophix。
- DroidPlugin和RePlugin由360开源,对原生应用侵入性小,对系统依赖小,稳定
- Tinker来自腾讯,使用Dex差分包的拆分和合并方式来实现热部署
- AndFix 和 Sophix来自阿里, 前者使用Native方式来实现热修复,后者不支持原生组件的替换
- Altas 和 Small 都是比较新的部署框架,据说都很牛逼
原理分析
-
ClassLoader原理
参考 热修复——深入浅出原理与实现【掘金】 -
Native原理
AndFix原理分析【简书】 -
InstantRun原理
参考 深度理解AndroidInstantRun【CSDN】
框架分析
使用开源修复框架来实现各种原理的示例,对比自己的实现,研究原理
常见热部署需求、方案、局限性、问题梳理
总结
android框架的核心部分包括:
1.由屏幕和触控能力抽象而来的窗口系统(图形绘制和事件分发),包括Window、View系列。
2.由其他硬件功能抽象而来的系统服务,比如Wifi、蓝牙、电源、相机、通话、GPS、多媒体等。
3.为应用提供的基础能力,比如应用框架Conetxt、Application,界面Activity、Fragment、Dialog,进程Service,通信Broadcast、Binder、Intent,数据SharePreference、Sqlite、ContentProvider,资源AssetManager等。
4.为应用提供的平台管理能力,比如PackageManager提供的包和权限的管理。
参考文献: