Android热更新

Android热更新

组件化

组件化和模块化其实一回事,都是拆分多个 module 进行开发,组件化的叫法更偏向封装系统功能,比如统一对话框封装, 络封装等,而模块化叫法更偏向业务方面,比如登录模块等。

插件化

App 的部分功能模块在打包的时候不以传统的方式打包进 apk 中,而是另一种方式封装到apk 内部,或者放在 络上适时下载,在需要的时候动态对这些功能模块进行加载,称之为插件化。

这些单独二次封装的功能模块 apk,称为插件,初始安装的 apk 称为宿主。

插件化基础是反射。

反射

Java 提供了关键字 public、private 用来限制代码之间的可见性,但又提供了反射来访问不可见方法。

可见特性的支持并不是为了保护代码不被别人使用,而是为了程序开发的简洁性。可见性的的支持提供的是 Safety 的安全,而不是 Security 的安全。可见性的支持是让程序的开发者不容易写出 bug ,而不是更容易外部被入侵。

反射的支持可以让开发者在可见性的不对外的时候,突破可见性的限制来调用自己需要的 API.

反射的使用:

DEX

class:java 编译后的文件,每一个类对应一个 class 文件。

dex:Dalvik Executable 把 class 打包到一起,一个 dex 可以包含多个 class 文件。

odex:Optimized DEX 针对系统的优化,例如某个方法的调用指令,会把虚拟机的调用转换为使用具体的 index,这样在执行的就不用再查找了。

oat:Optimized Android file Type,使用 AOT(Ahead-Of-Time compilation预先编译) 策略对 dex 预先编译成本地指令,这样在运行阶段就不需要再经历一次解释过程。

插件化原理

动态加载,通过自定义 ClassLoader 来加载新的 dex 文件,从而让程序员原本没有的类可以被使用。

插件化和热更新
  1. 插件化的内容在原 App 中没有,而热更新是原 App 中的内容做了改动
  2. 插件化在代码中有固定的入口,而热更新则可能改变了任何有一个位置的代码

热更新的原理

ClassLoader 的 dex 文件的替换,直接修改字节码

类加载过程

双亲委托机制,是一个带缓存的,从上到下(从父到子)的加载过程。

对于一个具体的 ClassLoader,先从自己的缓存中取,自己缓存中没有,就找父 ClassLoader 要(parent.loadClass()),父 View 也没有,就自己加载。(父View的加载流程和自己是一样的)

BaseDexClassLoader 的 findClass() 是通过它的 pathList.findClass(),它的 pathList.loadClass() 通过 DexPathList 的 dexElements 的 findClass(),所以热更新的关键在于,把补丁 dex 文件加载放进一个 Element,并且插入到 dexElements 这个数组的前面。

手写热更新

因为无法在更新之前就指定要更新谁,所以不能定义新的 ClassLoader,而只能选择对 ClassLoader 进行修改,让它能够加载补丁里面的类。

因为补丁中的类在之前的应用中已经存在,所以应该把补丁中的 Element 对象插入到 dexElements 的前面才行,插入到后面会被忽略掉。

具体的做法:

  1. 用补丁创建一个 PathClassLoader
  2. 把补丁 PathClassLoader 里面的 elements 插入到旧的 dexElements 前面去

尽早加载热更新,通常是把加载过程放在 Application.attachBaseContext()
热更新下载完之后需要先杀死程序才能让补丁生效
用 d8 把指定的 class 打包进 dex

sample

HotfixApplication

下载热更新包

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年2月25日
下一篇 2022年2月25日

相关推荐