Android Robust热修复方案实现原理

本文详细分析了Robust热修复的实现原理,包括Android APK生成过程、热修复的基本思路、代码插桩(ASM与Groovy Transform)以及如何通过DexClassLoader加载补丁。通过对源码的解读,揭示了Robust如何在编译期间插入ASM逻辑,以及在运行时通过自定义DexClassLoader实现补丁加载,完成代码修复。
摘要由CSDN通过智能技术生成

前言

本文旨在通过分析源码一步步分析Robust热修复的实现原理,前半部分首先分析一下Robust思路中运用到的技术方案;后半部分多为源码部分,即Robust对于技术方案的实现与运用。

1、关于Robust

Robust is an Android HotFix solution with high compatibility and high stability. Robust can fix bugs immediately without a reboot.

2、简述Android APK生成原理

image.png

首先我们来看一下生成.apk文件时会经过的一些主要步骤:
  • 资源文件打包,并生成对应的R.java文件(用于项目中对于资源文件的映射)
  • 将aidl编译生成对应的java文件(Android中对于跨进程交互的一种方式)
  • 将上述两类和我们编写的源码.java文件通过javac编译成.class文件
  • 通过dx脚本将所有的.class文件打包成为一个.dex文件(dex文件为Android中虚拟机所需加载的文件格式)
  • 通过apkbuilder将dex文件打包生成.apk文件

3、热修复基本实现思路

  • source code中对每一个方法体内进行插桩
  • 加载补丁包时,查找到对应方法体及类,使用DexClassLoader加载补丁类实现代码修复
原始代码
public long getIndex() {
   
        return 100;
    }
插桩后方法体
public static ChangeQuickRedirect changeQuickRedirect;
    public long getIndex() {
   
        if(changeQuickRedirect != null) {
   
            //PatchProxy中封装了获取当前className和methodName的逻辑,并在其内部最终调用了changeQuickRedirect的对应函数
            if(PatchProxy.isSupport(new Object[0], this, changeQuickRedirect, false)) {
   
                return ((Long)PatchProxy.accessDispatch(new Object[0], this, changeQuickRedirect, false)).longValue();
            }
        }
        return 100L;
    }
Patch类
public class StatePatch implements ChangeQuickRedirect {
   
    @Override
    public Object accessDispatch(String methodSignature, Object[] paramArrayOfObject) {
   
        String[] signature = methodSignature.split(":");
        if (TextUtils.equals(signature[1], "a")) {
   //long getIndex() -> a
            return 106;
        }
        return null;
    }
 
    @Override
    public boolean isSupport(String methodSignature, Object[] paramArrayOfObject) {
   
        String[] signature = methodSignature.split(":");
        if (TextUtils.equals(signature[1], "a")) {
   //long getIndex() -> a
            return true;
        }
        return false;
    }
}
A.代码插桩
ASM技术

首先,我们需要了解一个概念,ASM。ASM是一个Java字节码层面的代码分析及修改工具,它有一套非常易用的API,通过它可以实现对现有class文件的操纵,从而实现动态生成类,或者基于现有的类进行功能扩展。在Android的编译过程中,首先会将java文件编译为class文件,之后会将编译后的class文件打包为dex文件,我们可以利用class被打包为 dex 前的间隙,插入ASM相关的逻辑对class文件进行操纵。

Groovy Transform

Google在Gradle 1.5.0后提供了一个叫Transform的API,它的出现使得第三方的Gradle Plugin可以在打包dex之前对class文件进行进行一些操纵。我们本次就是要利用Transform API来实现这样一个Gradle Plugin
image.png
Transform具体操作的节点如上图所示,对于打包生成dex文件前的.class文件进行拦截,我们来看一看Transform为我们提供的可实现的方法:

方法名 含义
getInputTypes Transform需要处理的类型
getName Transform名称
getScopes Transform的作用域
isIncremental 增量编译开关
transform Transform处理文件的核心逻辑代码,此回调参数中可拿到要处理的.class文件集合

表格中可见,getNamgetInputTypes等方法均为Transform的配置项,最后的transform方法需要重点关注,我们想要实现上面的拦截.class文件并进行代码插桩操作就需要在此方法中实现。其中着重看一下方法的型参inputs,通过inputs可以拿到所有的class文件。inputs中包括directoryInputsjarInputsdirectoryInputs为文件夹中的class文件,而jarInputs为jar包中的class文件。

B.加载补丁
DexClassLoader

关于Java中的ClassLoader,大家熟知的基础概念就是通过一个类的全名加载得到这个类的class对象,进而可以得到其实例对象。
在Android中的ClassLoader基本运作远离与Java中类似,不过开发者无法自己实现ClassLoader进行自定义操作,官方的api为我们提供了两个ClassLoader的子类,PathClassLoaderDexClassLoader。虽然两者继承于BaseDexClassLoaderBaseDexClassLoader继承于ClassLoader,但是前者只能加载已安装的Apk里面的dex文件,后者则支持加载apkdex以及jar,也可以从SD卡里面加载。
从上述的概念我们可以得知,想要实现一个热修复的方案,就需要依赖外部的dex文件,那么就需要使用 DexClassLoader 来帮助实现。
我们来看一下 DexClassLoader 的构造方法:

参数 含义
dexPath 包含dex文件的jar包或apk文件路径
optimizedDirectory 释放目录,可以理解为缓存目录,必须为应用私有目录,不能为空
librarySearchPath native库的路径(so文件),可为空
parent 父类加载器(ClassLoader为双亲委派的加载方式,所以需要一个父级的ClassLoader)

4、Robust的实现

A.代码插桩

这一节中,我们来看一下Robust的具体实现方案以及一些大致的接入流程。
上一节讲述了Robust热修复方案中需要运用到的技术,接下来我们来看一看Robust的具体代码逻辑,如何将上述的思路融汇。
首先看一下Robust为接入用户提供的一个配置相关的文件

<?xml version="1.0" encoding="utf-8"?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值