type
status
date
slug
summary
tags
category
password
icon

热更新 / 热修复

不安装新版本的软件,直接从⽹络下载新功能模块来对软件进⾏局部更新

热更新和插件化的区别

区别有两点
  1. 插件化的内容在原 App 中没有,⽽热更新是原 App 中的内容做了改动
  1. 插件化在代码中有固定的⼊⼝,⽽热更新则可能改变任何⼀个位置的代码

热更新的原理

  • ClassLoader 的 dex ⽂件替换
  • 直接修改字节码

前置知识:loadClass() 的类加载过程

  • 宏观上:是⼀个带缓存的、从上到下的加载过程(即⽹上所说的「双亲委托机制」)
    • notion image
      上图有点错误,不是 loadClass 方法,是 findClass 方法
  • 对于具体的⼀个 ClassLoader:
    • 先从⾃⼰的缓存中取,取到了,就直接返回。
    • ⾃⼰没有缓存,就找⽗ ClassLoader 要(parent.loadClass())
    • ⽗ View 也没有,就⾃⼰加载(findClass()),加载成功就添加到缓存并返回。
  • BaseDexClassLoader 或者它的⼦类(DexClassLoader、PathClassLoader 等)的 findClass():
    • 通过它的 pathList.findClass()
    • 它的 pathList.loadClass() 通过 DexPathList 的 dexElements 的 findClass()
    • 所以热更新的关键在于,把补丁 dex ⽂件加载放进⼀个 Element,并且插⼊到 dexElements 这个数组的前⾯(插⼊到后⾯的话会被忽略掉)

⼿写热更新

  • 因为⽆法在更新之前就指定要更新谁;所以不能定义新的 ClassLoader,⽽只能选择对 ClassLoader 进⾏修改,让它能够加载补丁⾥⾯的类
  • 因为补丁的类在原先的 App 中已经存在,所以应该把补丁的 Element 对象插⼊到 dexElements 的 前⾯才⾏,插⼊到后⾯会被忽略掉。
  • 具体的做法:反射
    • ⾃⼰⽤补丁创建⼀个 PathClassLoader
    • 把补丁 PathClassLoader ⾥⾯的 elements 替换到旧的⾥⾯去
    • 注意:
      • 尽早加载热更新(通⽤⼿段是把加载过程放在 Application.attachBaseContext())
      • 热更新下载完成后在需要时先杀死程序才能让补丁⽣效
    • 优化:热更新没必要把所有内容都打过来,只要把改变的类拿过来就⾏了
      • ⽤ d8 把指定的 class 打包进 dex
    • 完整化:从⽹上加载
      • 再优化:把打包过程写⼀个 Task
      组件化|插件化常⻅项⽬架构的示例及培养⾃⼰的架构思路
      Loading...
      shuouyang
      shuouyang
      android开发 ReactNative开发 小程序开发
      最新发布
      AOSP 环境搭建
      2025-3-29
      View 绘制流程-源码解析
      2025-3-12
      HTTP
      2025-3-4
      JVM 虚拟机
      2025-2-28
      蓝牙-BLE-基础
      2025-2-28
      从 OkHttp 的原理来看 HTTP
      2025-2-19
      公告
      🎉热点信息🎉
      --- 1 ---
      Jet Brains 推出新的跨平台支持 Kotlin MultiPlatform
      --- 2 ---
      新的小巧便捷的依赖注入框架 Koin
      --- 3 ---
      新一代 API 查询语言 GraphQL