热修复之类加载方案 笔记整理

2024年Android最新热修复学习三:ClassLoader原理讲解,面试类书籍推荐 尤其是非计算机专业的同学,面试官一上来肯定是问你基础,要是基础表现不好很容易被扣上基础不扎实的帽子,常见的就那些,只要你平时认真思考过基本上面试是没太大问题的。,全部都是精华中的精华,我能面试到现在2-2资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。下面这份PDF是我翻阅了差不多3个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些。节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。 阅读详情

热修复分为:代码修复、资源修复、动态链接修复

其中,代码修复又分为:类加载方案、底层替换方案、Instant Run 方案。

本篇关于代码修复的类加载方案的笔记整理。

涉及源码版本为 Android 7.1.1。

参考文章:
1、Android热更新实现原理浅析
2、《Android 进阶解密》


1、理论基础

类加载方案是基于 Dex 分包方案的。

Dex 分包方案主要做的是在打包的时候将应用代码分成多个 Dex,将应用启动时必须用到的类和这些类的直接引用类放到主 Dex 中,其他代码放到次 Dex 中。当应用启动时先加载主 Dex,等到应用启动后再动态加载次 Dex。

而关于类的加载,就是遍历所有的 Dex 文件,从中去加载目标类。这里就涉及到了一个类 DexPathList。

更进一步的,是具体的是,则是涉及到类加载器。

对于类的加载,是通过 ClassLoader 来进行的,基于双亲委托模式,会先通过具体的加载器的父加载器来加载类,如果父加载器没加载到,则会调用自身的 findClass() 方法来自行加载。

涉及到的加载器包括 DexClassLoader 和 PathClassLoader。

  1. DexClassLoader 可以加载 dex 文件以及包含 dex 的压缩文件(apk 和 jar 文件),而且可以加载指定路径中的 dex 文件,包括外部存储空间的。
  2. PathClassLoader 则是 Android 系统用来加载系统类和应用程序的类。通常用来加载已经安装的 apk 的 dex 文件(安装的 apk 的 dex 文件会存在 /data/dalvik-cache 中)。

上述两个 ClassLoader 都继承自 BaseDexClassLoader。

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
                          String librarySearchPath, ClassLoader parent) {
    super(parent);
    // 实例化成员变量 pathList
    this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
    Class c = pathList.findClass(name, suppressedExceptions);
    if (c == null) {
        ... // 如果没有加载到目标  Class 则会抛出异常
    }
    return c;
}

可以看到,通过 BaseDexClassLoader#findClass() 会进一步调用前面说到的 DexPathList 类型的 pathList.findClass()。

public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;
        if (dex != null) {
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    if (dexElementsSuppressedExceptions != null) {
        suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
    }
    return null;
}

在 DexPathList#findClass() 中,会遍历 dexElements 数组,该数组的元素的为 DexPathList.Element 类型,而其内部又封装了 DexFile 成员变量,该变量就对应着实际的 dex 文件,更进一步的说,加载 Class 实际上是通过 DexFile 来实现的。

因此,类加载方案的实现,就是将补丁 dex 对应的 Element 插入到应用对应的加载器的 pathList 的 dexElements 数组的靠前位置,从而使得后面同名的 Class 不被加载。

2、具体实现

参考 Demo:HotFixDemo

补充两点:

(1)是关于 CLASS_ISPREVERIFIED 的问题(涉及到 Dalvik 虚拟机),具体参见:Android 冷启动热修复技术杂谈,因此在测试的时候要使用基于 ART 虚拟机的机型,即 Android 5.0 及以上版本。

(2)由于 Android 9.0 隐藏了部分 API,所以无法实现反射替换对应的 dexElements 数组,因此在测试的要使用 9.0 以下的手机。

关键部分代码:

public void doHotFix(Context context) throws IllegalAccessException, NoSuchFieldException, ClassNotFoundException {
    if (context == null) {
        return;
    }
    // 补丁存放目录为 /storage/emulated/0/Android/data/com.lxbnjupt.hotfixdemo/files/patch
    // 注意,这里的 dexFile 是一个目录
    File dexFile = context.getExternalFilesDir(DEX_DIR);
    if (dexFile == null || !dexFile.exists()) {
        Log.e(TAG,"热更新补丁目录不存在");
        return;
    }
    // 得到 new DexClassLoader 时需要的存储路径
    File odexFile = context.getDir(OPTIMIZE_DEX_DIR, Context.MODE_PRIVATE);
    if (!odexFile.exists()) {
        odexFile.mkdir();
    }
    // 获取 /storage/emulated/0/Android/data/com.lxbnjupt.hotfixdemo/files/patch 
    // 目录下的所有文件,用于找出里面的补丁 dex
    File[] listFiles = dexFile.listFiles();
    if (listFiles == null || listFiles.length == 0) {
        return;
    }
    
    // 获取补丁 dex 文件路径集合
    String dexPath = getPatchDexPath(listFiles);
    String odexPath = odexFile.getAbsolutePath();
    // 获取应用对应的 PathClassLoader
    PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
    
    // 构建 DexClassLoader,用于加载补丁 dex
    // DexClassLoader 构造方法的四个参数:
    //      第一个:dex 文件相关路径集合,多个路径用文件分隔符分隔,默认文件分隔符为 :
    //      第二个:解压的 dex 文件的存储路径,必须是一个内部存储路径
    //      第三个:包含 C/C++ 库的路径集合,可以为 null
    //      第四个:父加载器
    DexClassLoader dexClassLoader = new DexClassLoader(dexPath, odexPath, null, pathClassLoader);
    // 这里要新 new 一个 DexClassLoader 的原因就是为了借助系统来构建出补丁 dex 对应
    // 的 Element 元素的数组,从而插入到应用的 PathClassLoader 的 
    // pathList.dexElements 中
    
    // 通过反射获取 PathClassLoader 的 Element 数组
    Object pathElements = getDexElements(pathClassLoader);
    // 获取构建的 DexClassLoader 的 Element 数组
    Object dexElements = getDexElements(dexClassLoader);
    // 合并 Element 数组
    Object combineElementArray = combineElementArray(pathElements, dexElements);
    // 通过反射,将合并后的 Element 数组赋值给 PathClassLoader 中 pathList 里面的
    // dexElements 变量
    setDexElements(pathClassLoader, combineElementArray);
}

注意,由于类加载之后是无法被主动卸载的,因此类加载方法需要重启 App 后让 ClassLoader 重新加载新的类。

而且重启应用之后,如果没有触发加载补丁类,则应用还是会加载原来的 BUG 类。

通过类加载机制动手实现Android热修复 本demo是一套完整的热修复,包括:检测服务器上是否存在dex补丁、下载dex补丁、安装dex补丁,实现热修复。基本是一套完整流程,仅做参考,有问题可以一起讨论 立即下载

相关推荐

ESP32对接百度智能云语音识别:从硬件配置到API调用的完整指南

本文详细介绍了ESP32对接百度智能云语音识别的完整流程,从硬件配置到API调用,涵盖麦克风选择、音频处理、错误处理及性能优化等关键环节。通过实战案例展示如何实现低成本、高效率的语音交互方案,特别适合智能硬件开发者参考。

weixin_29198045的博客 372

Java类加载机制(通俗易懂版)

类是在运行期间第一次使用时,被类加载器动态加载至JVM。JVM不会一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。Java类加载机制是指在Java程序运行时,将类文件加载到内存中的一系列步骤。Java的类加载机制遵循着“按需加载”的原则,也就是说,只有在需要用到某个类的时候,才会将这个类的相关信息加载到内存中。这种“按需加载”的设计使得Java程序具备了很好的灵活性和效率。

weixin_52572813的博客 1392

从零开始理解异构算力调度:全国一体化算力算网平台实战解析

本文深入解析了异构算力调度技术在全国一体化算力算网平台中的实战应用。通过资源抽象层设计、动态感知引擎和跨云调度算法,实现AI训练任务的高效资源分配,显著提升计算效率并降低成本。特别针对GPU等异构算力的智能调度方案,为多云协同环境下的AI开发提供实用指南。

weixin_28730927的博客 332

热修复技术实践之类加载方案

项目地址 类加载方案的原理是在app重新启动后让Classloader去加载新的类。因为在 app运行到一半的时候,所有需要发生变更的类已经被加载过了,在Android上是 无法对一个类进行卸载的。如果不重启,原来的类还在虚拟机中,就无法加载新类。 因此,只有在下次重启的时候,在还没走到业务逻辑之前抢先加载补丁中的新类,这 样后续访问这个类时,就会Resolve为新类。从而达到热修...

SolarLove的博客 210

【鸿蒙游戏上架审核规范指南】

华为鸿蒙游戏上架审核规范指南摘要

weixin_44161102的博客 913

YOLOv8损失函数升级:从CIoU到Wise-IoU v3的实战调优与避坑指南

本文详细介绍了如何将YOLOv8的损失函数从CIoU升级到Wise-IoU v3,以提升目标检测性能,特别是在小目标检测和样本不均衡场景下的表现。通过实战调优步骤和避坑指南,帮助开发者有效应用Wise-IoU v3的动态聚焦机制和单调性控制,显著提升模型精度和训练稳定性。

weixin_33737774的博客 590

一篇文章搞懂热修复类加载方案原理

ClassLoader 类型 Java 中的 ClassLoader 可以加载 jar 文件和 Class文件(本质是加载 Class 文件),这一点在 Android 中并不适用,因为无论 DVM 还是 ART 它们加载的不再是 Class 文件,而是 dex 文件。 Android 中的 ClassLoader 类型和 Java 中的 ClassLoader 类型类似,也分为两种类型,分别是系...

weixin_33834075的博客 436

CCC数字钥匙3.0标准解读(22)

介绍设备制造商服务器和车辆制造商服务器之间的通信协议.

weixin_41738640的博客 1748

Android热修复技术 --- 类加载机制

热修复前言 类加载机制

qq_33235287的博客 4283

宝塔面板磁盘扩容后不生效?5步搞定Linux服务器磁盘空间更新(附详细命令)

本文详细解析了Linux服务器磁盘扩容后宝塔面板显示不生效的常见问题。通过理解磁盘、分区、文件系统三层逻辑,提供5步解决方案:检查磁盘状态、安装growpart工具、扩展分区、使用resize2fs命令扩展文件系统,并最终验证结果。文中附有详细命令和针对XFS、LVM等进阶场景的指南,帮助用户彻底解决磁盘空间更新问题。

weixin_29271263的博客 127

使用 Simulink 搭建一个地震信号反射系数反演与滤波联合仿真的系统模型

《Simulink地震信号处理仿真指南》摘要:本文详细介绍了使用Simulink进行地震信号反射系数反演与滤波联合仿真的完整流程。从创建模型、生成含噪合成地震记录(包含子波卷积与随机反射系数),到设计滤波模块(带通/小波/自适应滤波)和实现反演算法(Wiener-Hopf方程/RLS方法),最后通过可视化模块分析结果。教程涵盖理论准备、7个实施步骤、优化建议及实际应用场景,为地震勘探、地质调查等领域提供标准化的信号处理仿真方案,特别适合需要掌握地震信号反演与实时滤波技术的工程人员学习。

amy_mhd的博客 113

APP 热修复都懂了,你会 SDK 热修复吗?最全方案在这里!(3)

主要是代码热更,无so库、资源更新需求;实时性要求高,因为一旦出问题,对业务方的影响极大;兼容性要求高,你无法预料到业务方的活跃用户都有啥机型。

2401_84132544的博客 910

FLUENT Meshing Watertight Geometry工作流入门 - 5 生成表面网格

我们学习在生成表面网格任务下的不同输入。讨论了局部尺寸控制与全局尺寸控制的影响。最后,讨论了如何改进表面网格,以实现好的体网格质量。

B_etter_Man的博客 5632

Android 几种流行热修复方案整理

Android 热修复 Dexposed 基于Xposed的AOP框架,方法级粒度,可以进行AOP编程、插桩、热补丁、SDK hook等功能。 Xposed需要Root权限,是因为它要修改其他应用、系统的行为,而对单个应用来说,其实不需要root。 Xposed通过修改Android Dalvik运行时的Zygote进程,并使用Xposed Bridge来hook方法并注入自己的

0℃冰糖 1613

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

探索Android开源框架 - 11. 热修复原理

热修复技术介绍 重新发布版本代价大,成本高,不及时,用户体验差,对此有几种解决方案: Hybird:原生+H5混合开发,缺点是人工成本搞,用户体验不如纯原生方案好; 插件化:移植成本高,对老代码的改造费时费力,而且无法动态修改; 热修复技术,将补丁上传到云端,app可以直接从云端下来补丁直接应用; 热修复技术对于国内开发者来说是一个比较实用的功能,可以解决如下问题: 发布新版本代价较大,用户下载安装成本高; 版本更新的效率问题,需要较长时间来完成版本覆盖; 版本更新的升级率问题,不升级版本的用

o118abcdef的博客 1773

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Android热修复终极指南:10分钟掌握主流热修复方案

🔥 **热修复技术**是Android开发中的重要利器,能够在不重新发布应用的情况下修复线上bug。如果你还在为每次小bug都要重新发布应用而烦恼,那么这篇文章将为你打开一扇新的大门!🚀 ## 什么是Android热修复? **Android热修复**(HotFix)是一种动态修复应用bug的技术,它允许开发者在应用运行过程中修复代码问题,无需用户重新下载安装应用。这种技术特别适合修复紧急

gitblog_00175的博客 404

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

APP 热修复都懂了,你会 SDK 热修复吗?最全方案在这里

方案一:JAR 替换 步骤 从服务端下载 jar -> 通过反射,加载jar -> 创建相关对象并且操作之。 方案参考: Android SDK热修复机制简析以实现 优缺点 优点: 无兼容问题 缺点: 反射消耗性能; jar 包如果体积大,整个下载就很不友好; 确定改动的代码范围繁琐,维护麻烦。 方案一改进:子 JAR 替换 步骤 针对 jar 包体积大的情况,我们可以考虑对 sdk 项目进行拆包(拆module),分成小的 jar 包和主包 主包负责反射加载,如果需

m0_66685318的博客 507

APP 热修复都懂了,你会 SDK 热修复吗?最全方案在这里!(1)

主要是代码热更,无so库、资源更新需求;实时性要求高,因为一旦出问题,对业务方的影响极大;兼容性要求高,你无法预料到业务方的活跃用户都有啥机型。今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题。

2301_79655511的博客 865

java热修复实例

关于java热修复的一次尝试

李耳的代码之路 3470

APP 热修复都懂了,你会 SDK 热修复吗?最全方案在这里!

主要是代码热更,无so库、资源更新需求;实时性要求高,因为一旦出问题,对业务方的影响极大;兼容性要求高,你无法预料到业务方的活跃用户都有啥机型。

2401_84412961的博客 77

APP 热修复都懂了,你会 SDK 热修复吗?最全方案在这里!(2)

主要是代码热更,无so库、资源更新需求;实时性要求高,因为一旦出问题,对业务方的影响极大;兼容性要求高,你无法预料到业务方的活跃用户都有啥机型。总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

2401_84149557的博客 613

Android热修复核心原理介绍

对网络上热修复方案和原理的文章和三方框架进行了二次整理,让读者对热修复方案和原理有个整体的认知。总的来说热修复不是简单的一项技术,更贴切的说是一种解决方案,不仅涉及到APP端的补丁生成和生效技术,还涉及系统兼容性、开发过程代码管理、补丁管理系统等。除非有足够的人力物力支持,否则在生产环境中引入热修复还是推荐使用阿里、腾讯等大厂的现成方案,不推荐自己造轮子。

csfchh的博客 2386

Android热修复原理与实战_安卓自己实现热修复(2),2024年最新重难点整理

果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)**[外链图片转存中…(img-XkezW8LM-1712648077056)]

2401_83974783的博客 824
上一篇: 【LeetCode】115. 不同的子序列
下一篇: 点击事件分发机制 关键源码笔记
OneDeveloper
博客等级 码龄9年 61粉丝 161原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值