Android热修复技术——QQ空间补丁方案解析(1)

news/2024/11/23 3:29:55/

传统的app开发模式下,线上出现bug,必须通过发布新版本,用户手动更新后才能修复线上bug。随着app的业务越来越复杂,代码量爆发式增长,出现bug的机率也随之上升。如果单纯靠发版修复线上bug,其较长的新版覆盖期无疑会对业务造成巨大的伤害,更不要说大型app开发通常涉及多个团队协作,发版排期必须多方协调。
那么是否存在一种方案可以在不发版的前提下修复线上bug?有!而且不只一种,业界各家大厂都针对这一问题拿出了自家的解决方案,较为著名的有腾讯的Tinker和阿里的Andfix以及QQ空间补丁。网上对上述方案有很多介绍性文章,不过大多不全面,中间略过很多细节。笔者在学习的过程中也遇到很多麻烦。所以笔者将通过接下来几篇博客对上述两种方案进行介绍,力求不放过每一个细节。首先来看下QQ空间补丁方案。

1. Dex分包机制

大家都知道,我们开发的代码在被编译成class文件后会被打包成一个dex文件。但是dex文件有一个限制,由于方法id是一个short类型,所以导致了一个dex文件最多只能存放65536个方法。随着现今App的开发日益复杂,导致方法数早已超过了这个上限。为了解决这个问题,Google提出了multidex方案,即一个apk文件可以包含多个dex文件。
不过值得注意的是,除了第一个dex文件以外,其他的dex文件都是以资源的形式被加载的,换句话说就是在Application.onCreate()方法中被注入到系统的ClassLoader中的。这也就为热修复提供了一种可能:将修复后的代码达成补丁包,然后发送到客户端,客户端在启动的时候到指定路径下加载对应dex文件即可。
根据Android虚拟机的类加载机制,同一个类只会被加载一次,所以要让修复后的类替换原有的类就必须让补丁包的类被优先加载。接下来看下Android虚拟机的类加载机制。

2. 类加载机制

Android的类加载机制和jvm加载机制类似,都是通过ClassLoader来完成,只是具体的类不同而已:
1
Android系统通过PathClassLoader来加载系统类和主dex中的类。而DexClassLoader则用于加载其他dex文件中的类。上述两个类都是继承自BaseDexClassLoader,具体的加载方法是findClass:

public class BaseDexClassLoader extends ClassLoader {private final DexPathList pathList;/*** Constructs an instance.** @param dexPath the list of jar/apk files containing classes and* resources, delimited by {@code File.pathSeparator}, which* defaults to {@code ":"} on Android* @param optimizedDirectory directory where optimized dex files* should be written; may be {@code null}* @param libraryPath the list of directories containing native* libraries, delimited by {@code File.pathSeparator}; may be* {@code null}* @param parent the parent class loader*/public BaseDexClassLoader(String dexPath, File optimizedDirectory,String libraryPath, ClassLoader parent) {super(parent);this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {List<Throwable> suppressedExceptions = new ArrayList<Throwable>();Class c = pathList.findClass(name, suppressedExceptions);if (c == null) {ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);for (Throwable t : suppressedExceptions) {cnfe.addSuppressed(t);}throw cnfe;}return c;}
}

从代码中可以看到加载类的工作转移到了pathList中,pathList是一个DexPathList类型,从变量名和类型名就可以看出这是一个维护Dex的容器:

/*package*/ final class DexPathList {private static final String DEX_SUFFIX = ".dex";private static final String JAR_SUFFIX = ".jar";private static final String ZIP_SUFFIX = ".zip";private static final String APK_SUFFIX = ".apk";/** class definition context */private final ClassLoader definingContext;/*** List of dex/resource (class path) elements.* Should be called pathElements, but the Facebook app uses reflection* to modify 'dexElements' (http://b/7726934).*/private final Element[] dexElements;/*** Finds the named class in one of the dex files pointed at by* this instance. This will find the one in the earliest listed* path element. If the class is found but has not yet been* defined, then this method will define it in the defining* context that this instance was constructed with.** @param name of class to find* @param suppressed exceptions encountered whilst finding the class* @return the named class or {@code null} if the class is not* found in any of the dex files*/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;}
}

DexPathListfindClass也很简单,dexElements是维护dex文件的数组,每一个item对应一个dex文件。DexPathList遍历dexElements,从每一个dex文件中查找目标类,在找到后即返回并停止遍历。所以要想达到热修复的目的就必须让补丁dex在dexElements中的位置先于原有dex:
23
这就是QQ空间补丁方案的基本思路,接下来的博文笔者将以一个实际的例子详述QQ空间补丁热修复的过程


http://www.ppmy.cn/news/395575.html

相关文章

Android热修复技术——QQ空间补丁方案解析(3)

如前文所述&#xff0c;要想实现热更新的目的&#xff0c;就必须在dex分包完成之后操作字节码文件。比较常用的字节码操作工具有ASM和javaassist。相比之下ASM提供一系列字节码指令&#xff0c;效率更高但是要求使用者对字节码操作有一定了解。而javaassist虽然效率差一些但是使…

记录一次confluence无法创建新空间的问题修复

不知道从神马时候开始&#xff0c;confluence突然创建不了空间&#xff1b; 1、通过confluence管理员进入故障排除工具&#xff1b; 2、查看具体的问题&#xff1a; 通过日志分析器&#xff0c;最有可能就是下面的一个错误&#xff1b; 打开官方指引&#xff1a; Create Pag…

qq空间找不到服务器或dns错误,qq空间无法正常打开怎么办

在登录QQ空间的时候&#xff0c;有些用户会遇到“如果您看到这个提示,说明QQ空间无法正常打开,请尝试使用空间小助手修复”的提示。今天学习啦小编给你分享一下qq空间无法正常打开的解决方法&#xff0c;欢迎阅读。 qq空间无法正常打开的解决过程 故障排查方法 ping一下QQ空间的…

模仿qq空间评论以及回复

先看需求是怎么样的&#xff1a; 再看评论表结构的设计&#xff1a; create table t_comment (id varchar(32) primary key, #主键Idcustomer_id varchar(32) not null, #用户Idparent_comment_id varchar(32) not null, #父评论Idcontent_id varchar(32) not null, #评论对象的…

Android热修复技术——QQ空间补丁方案解析(2)

接下来的几篇博客我会用一个真实的demo来介绍如何实现热修复。具体的内容包括&#xff1a; 如何打包补丁包如何将通过ClassLoader加载补丁包 1. 创建Demo demo很简单&#xff0c;创建一个只有一个Activity的demo&#xff1a; package com.biyan.demo public class MainActi…

一键删除qq空间说说

var delay1 2500; var delay2 2200; var delay3 4000; var i 0; var next “#pager_next_”; function del() {try{document.querySelector(‘.app_canvas_frame’).contentDocument.querySelector(‘.del_btn’).click();setTimeout(“yes()”, delay2); }catch(err){nex…

QQ空间 安卓App热补丁动态修复技术介绍

【原文地址 点击打开链接】 【各自热修复框架介绍 点击打开链接】 【AndFix使用说明 AndFix使用说明】 AndFix与Nuwa对比 Nuwa是另一个热补丁框架&#xff0c;原理是基于QQ空间团队提出的安卓App热补丁动态修复技术介绍。 与Nuwa相比&#xff0c;AndFix有一下优点&#xf…

电脑修复损坏文件--修复命令;系统盘磁盘空间不足

目录 sfc/scannow--修复损坏的系统文件命令解析command parse步骤 命令修复磁盘&#xff1b;磁盘空间的释放输入“sfc /purgecache”命令&#xff08;不含双引号&#xff0c;下同&#xff09;输入“cleanmgr”命令输入“CHKDSK D:/F”&#xff0c;修复D驱动器号 sfc/scannow–修…