Android 加载热补丁简单例子

本文深入剖析了安卓热修复技术的实现原理,通过实例展示了如何利用反射和类加载机制替换应用中的类,实现无需重新安装即可修复应用bug或更新功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先定义一个功能类,类里定义一个test方法

public class UserInfoManager {

    public UserInfoManager(){
    }

    public void test(Context context) {
        Toast.makeText(context,"我是"+UserInfoManager.class.getName()+"",Toast.LENGTH_LONG).show();
    }
}

然后定义一个针对改功能使用的接口类

public class Manager {

    private UserInfoManager userInfoManager;

    public Manager() {
        userInfoManager = new UserInfoManager();
    }

    public void test(Context context) {
        if (userInfoManager != null) {
            userInfoManager.test(context);
        }
    }
}

在Activity中的按钮点击事件中使用如下方法调用

manager = new Manager();
manager.test(this);

执行后可以看到如下弹框

假如这个是一个线上APP的一段逻辑,这一段业务逻辑有问题,我们现在需要更改他;热修复的要求是直接替换这个类,用户只需要更新自己需要的类就可以完成替换;在这个要求下,我们首先需要想到的是在这一段逻辑中加入可更新类对象的方法,利用反射可以这样实现

实现一个新类继承自UserInfoManager

public class UserInfoManagerFix extends UserInfoManager {

    public UserInfoManagerFix(){
    }

    @Override
    public void test(Context context) {
        Toast.makeText(context,"我是"+UserInfoManagerFix.class.getName()+"",Toast.LENGTH_LONG).show();
    }
}

然后更新按钮点击的实现方式,利用反射替换UserInfoManager为UserInfoManagerFix

manager = new Manager();
//替换补丁类
try {
    //new一个补丁
    userInfoManagerFix = new UserInfoManagerFix();
    //获取需要替换的对象字段
    Field mUserInfoManagerA = manager.getClass().getDeclaredField("userInfoManager");
    mUserInfoManagerA.setAccessible(true);
    //核心,替换类引用
    mUserInfoManagerA.set(manager, userInfoManagerFix);
    //再次执行方法
    manager.test(this);
} catch (Exception e) {
    e.printStackTrace();
}

执行后,可以看到如下

是不是已经执行的是补丁类的方法

我们需要的是将这个类打包成补丁进行网络下载后加载,我简单的将其打包成jar,选择Build->Make Project-,完成后在

app\build\intermediates\javac\debug\classes\包名\下找到类名.class文件,然后利用jar 命令转化成一个jar。

我转化后放在assets下,如图

然后更改下点击事件

manager = new Manager();
//复制补丁到指定路径,模拟网络下载
String hotFixLibPath = getExternalCacheDir().getAbsolutePath() + File.separator + "UserInfoManagerFix.jar";
try {
    InputStream inputStream = getAssets().open("UserInfoManagerFix.jar");
    File file = new File(hotFixLibPath);
    file.deleteOnExit();
    file.createNewFile();
    FileOutputStream outputStream = new FileOutputStream(file);
    int read = -1;
    while ((read = inputStream.read()) > 0) {
        outputStream.write(read);
    }
    outputStream.flush();
    outputStream.close();
} catch (Exception e) {
}
//利用DexClassLoader加载补丁,然后替换
String hotFixOutPath = getExternalCacheDir().getAbsolutePath();
DexClassLoader classLoader = new DexClassLoader(hotFixLibPath, hotFixOutPath, null, getClassLoader());
try {
    Class hotFixCls = classLoader.loadClass("com.example.hotfix.managerfix.UserInfoManagerFix");
    Object hotFixObj = hotFixCls.newInstance();
    //找到字段进行替换
    Field mUserInfoManagerA = manager.getClass().getDeclaredField("userInfoManager");
    mUserInfoManagerA.setAccessible(true);
    mUserInfoManagerA.set(manager, hotFixObj);
    //再次执行方法
    manager.test(this);
} catch (Exception e) {
    e.printStackTrace();
}

执行点击

可以看到执行的是jar包中的方法。整个jar包也就2Kb

如果真的有这么一个需求,那么更新2kb的jar包总比更新整个APP体验好的多。

现在基本实现了一个简单的,可以进行热修复目的小Demo。

插件化和虚拟化双开APP的原理基本也如上。其核心过程都是更改系统原有的一些流程,因此需要从安卓源码进行分析;并且如果需要兼容不同版本系统,还需要在针对不同代码写不用的hook过程。


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值