技术分享

Android热修复原理及应用

为什么做这个分享?

1 之前分享主题以代码规范、业务重构、设计优化相关介绍的比较多,再分享此类主题可能重复比较多。

2 平时需求以业务需求为主,纯技术的不算太多,而Android热修复算是一个比较火的技术主题

3 Github上热度榜上,目前月内最火热的Java开源框架就是 tinker

一 什么是热修复

二 热修复原理及两种主要实现方式

三 Tinker简介及一个示范案例

四 Tinker框架结构及代码流程分析

一 什么是热修复

背景

当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码,也要付出巨大的成本进行换包和重新发布。

这时候就提出一个问题:有没有办法以补丁的方式动态修复紧急Bug,不再需要重新发布App,不再需要用户重新下载,覆盖安装?

能够解决该问题的技术方案就称为热修复!

热修复定义 用户不用重新下载一个新的apk安装,而是直接下载一个补丁包,通过补丁来替换一些出现bug的类, 下载补丁的过程用户一般是感觉不到的,表面上看是直接修复了bug.

二 热修复原理及两种主要实现方式

如何实现这个技术方案 有以两个流派

Native流派,代表有阿里的Dexposed、AndFix与腾讯的内部方案KKFix;

Java流派, 代表有Qzone的超级补丁、大众点评的Nuwa、百度金融的RocooFix, 饿了么的Amigo以及美团的Robust

其中以下几个框架已经开源

Dexposed https://github.com/alibaba/dexposed

AndFix https://github.com/alibaba/AndFix

Nuwa https://github.com/jasonross/Nuwa

RocooFix https://github.com/dodola/RocooFix

Amigo https://github.com/eleme/Amigo

二 热修复原理及几种实现方式

这两种方式代表着什么 具体原理是怎样的 这得从Android打包说起

Android应用所使用的编程语言是Java语言,编译时通过JDK将Java源程序转换成标准的Java字节码文件(.class文件),再通过工具软件DX把所有的字节码文件转换转成Android dex文件(.dex),最后使用Android打包工具(aapt)将dex文件、资源文件以及AndroidManifext.xml(二进制格式)组合成一个应用程序包(.apk),应用程序包发布到手机上就可以运行了。

其中Dex文件的生成方式如下

Java编译器创建JVM字节码后,Dalvik的dx编译器删除.class文件,重新把它们编译成Dalvik字节码,然后把它们写进一个.dex文件中。这个过程包括翻译、重构、解释程序的基本元素(常量池、类定义、数据段)

常量池描述了所有的常量,包括引用、方法名、数值常量等

类定义包括访问标志、类名等基本信息

数据段包含各种被VM执行的函数代码以及类和函数的相关信息(例如Dalvik虚拟机所需要的寄存器数据、局部变量表、操作数堆栈大小),还有实例变量

Dex文件头主要包括校验及其它结构的偏移地址和长度信息 文件头结构表如下 整个dex文件结构还是挺复杂的

说完了整个打包流程 那两个流派到底是什么?先说结论

1 Native流派核心是替换函数,将Java方法的属性设为native转到JNI层处理,在JNI中又把方法指针指向了Java Hook,在hook中回调其他Java方法,Java->Native Hook->Java Fix,最终回调到任意的目标方法.

2 Java流派核心是替换dex,有点像插件动态加载,原理是虚拟机在加载类--即从类名映射到class文件的过程时顺序遍历系统中dexElements组,dexElements持有应用所有dex,一旦其中element能够成功加载立即返回目标类对应的class.于是可以通过反射层层获取各种成员各种变量,最后获取到dexElements这个成员,将这个数组arrayCopy一份,顺便在复制出来的数组第0个位置放上自己的dex,最后将复制体set回dexElements,实现了将class替换成自己的。

Java流派可能解释比较抽象 因为里面涉及到Android的ClassLoader体系

ClassLoader体系

android中加载类一般使用的是PathClassLoader和DexClassLoader

1 PathClassLoader  //Android是使用这个类作为其系统类和应用类的加载器。并且对于这个类,只能去加载已经安装到Android系统中的apk文件

2 DexClassLoader  //该类可以用来从.jar和.apk类型的文件内部加载classes.dex文件,可以用来执行非安装的程序代码

这两个类都继承自BaseDexClassLoader。

加载类简单来说就是给个classname,然后去findClass,细节可以参考BaseDexClassLoader中代码

BaseDexClassLoader中代码

你可能感兴趣的:(技术分享)