android热修复——自己做个热修复

news/2024/7/5 6:39:53

类的加载机制
这里写图片描述

需要注意的地方

  • 1.每次生成之后一定要测试;
  • 2.尽量的不要分包,不要分多个dex
  • 3.混淆的时候,设计到NDK AndFix.java 不要混淆
  • 4.生成包之后一般会加固什么的,这个时候生成的差分包,一定要在之前去生成。
  • 5.既然是去修复方法,第一个不能增加成员变量,不能增加方法

源码

public class FixDexManager {
    private Context mContext;
    private File mDexFile;
    private static final String TAG = FixDexManager.class.getSimpleName();
    private Object applicationDexElements;

    public FixDexManager(Context context) {
        this.mContext = context;
        //可以访问的dex目录
        mDexFile = context.getDir("odex", Context.MODE_PRIVATE);
    }

    /**
     * 修复dex包
     */
    public void fixDex(String fixDexPath) throws Exception {

        //2.获取下载好的补丁 dexElement
        //2.1移动到系统能够访问的 dex目录下
        File srcFile = new File(fixDexPath);
        if (!srcFile.exists()) {
            throw new FileNotFoundException(fixDexPath);
        }
        File destFile = new File(mDexFile, srcFile.getName());
        if (destFile.exists()) {
            Log.d(TAG, "patch [" + fixDexPath + "] has be loaded.");
            return;
        }
        copyFile(srcFile, destFile);
        //2.2ClassLoader读取fileDex路径
        List<File> fixDexFiles = new ArrayList<>();
        fixDexFiles.add(destFile);


    }

    /**
     * 把dexElement注入到classLoader
     */
    private void injectDexElement(ClassLoader classLoader, Object dexElements) throws Exception {
        //1.先获取pathList
        Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList");
        //所有属性都可以获得
        pathListField.setAccessible(true);
        Object pathList = pathListField.get(classLoader);
        //2.获得pathList中的dexElements
        Field dexElementsFiled = pathList.getClass().getDeclaredField("dexElements");
        dexElementsFiled.setAccessible(true);
        //注入
        dexElementsFiled.set(dexElementsFiled.get(pathList), dexElements);
    }

    /**
     * 合并数组
     */
    private static Object combineArray(Object arrayLhs, Object arrayRhs) {
        Class<?> localClass = arrayLhs.getClass().getComponentType();//获得数组对象
        int i = Array.getLength(arrayLhs);
        int j = Array.getLength(arrayRhs);
        Object result = Array.newInstance(localClass, j);
        for (int k = 0; k < j; ++k) {
            if (k < i) {
                Array.set(result, k, Array.get(arrayLhs, k));
            } else {
                Array.set(result, k, Array.get(arrayLhs, k - 1));
            }
        }
        return result;
    }

    /**
     * 将路径复制到目标文件下
     */
    public static void copyFile(File src, File dest) throws IOException {
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            if (!dest.exists()) {
                dest.createNewFile();
            }
            inChannel = new FileInputStream(src).getChannel();
            outChannel = new FileOutputStream(dest).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally {
            if (inChannel != null) {
                inChannel.close();
            }
            if (outChannel != null) {
                outChannel.close();
            }
        }
    }

    /**
     * 从classLoader中获取
     *
     * @param classLoader
     */
    private Object getDexElementsByClassLoader(ClassLoader classLoader) throws Exception {
        //1.先获取pathList
        Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList");
        //所有属性都可以获得
        pathListField.setAccessible(true);
        Object pathList = pathListField.get(classLoader);
        //2.获得pathList中的dexElements
        Field dexElementsFiled = pathList.getClass().getDeclaredField("dexElements");
        dexElementsFiled.setAccessible(true);
        return dexElementsFiled.get(pathList);
    }

    /**
     * 加载全部的修复包
     */
    public void loadFixDex() throws Exception {
        File[] dexFiles = mDexFile.listFiles();
        List<File> fixDexFiles = new ArrayList<>();
        for (File dexFile : dexFiles) {
            if (dexFile.getName().endsWith(".dex")) {
                fixDexFiles.add(dexFile);
            }
        }
        fixDexFiles(fixDexFiles);
    }

    /**
     * 修复dex
     */
    private void fixDexFiles(List<File> fixDexFiles) throws Exception {
        //1.先获取已运行的dexElement
        ClassLoader applicationClassLoader = mContext.getClassLoader();
        Object dexElements = getDexElementsByClassLoader(applicationClassLoader);
        File optimizedDirectory = new File(mDexFile, "odex");
        if (!optimizedDirectory.exists()) {
            optimizedDirectory.mkdir();
        }
        //修复
        for (File fixDexFile : fixDexFiles) {

            ClassLoader fixDexClassLoader = new BaseDexClassLoader(
                    fixDexFile.getAbsolutePath(),//dex路径 必须要在应用目录下的dex文件中
                    optimizedDirectory,//解压路径
                    null,//.so文件的位置
                    applicationClassLoader//父classloader
            );
            Object fixDexElement = getDexElementsByClassLoader(fixDexClassLoader);

            //3.把补丁的dexElement插到已经运行好的dexElements的最前面
            //合并数组
            applicationDexElements = combineArray(dexElements, fixDexElement);

        }
        //注入到原来的类中applicationClassLoader
        injectDexElement(applicationClassLoader, applicationDexElements);
    }
}

http://www.niftyadmin.cn/n/3648865.html

相关文章

Android系统权限配置详解

Android 权限控制代码分析 前在文章介绍过android系统管理层次&#xff1a;http://blog.csdn.net/andyhuabing/article/details/7030212 &#xff0c;这里就核心代码分析一下 android系统充分利用了linux的用户权限管理方法&#xff0c;所以如果需要移植到其它系统&#xff0c…

自己动手搭建数据库框架

首先IDaoSupport接口&#xff0c;有查询&#xff0c;插入单条数据&#xff0c;批量插入&#xff0c;删除&#xff0c;更新 public interface IDaoSupport<T> {void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz);// 插入数据public long insert(T t);// 批…

关于软件的架构设计

好的开始相当于成功一半 开始之初的架构设计决定着软件产品的生死存亡。“好的开始相当于成功一半”。 开始的架构设计也是最难的&#xff0c;需要调研同类产品的情况以及技术特征&#xff0c;了解当前世界上对这种产品所能提供的理论支持和技术平台支持。再结合自己项目的特点…

javascript递归_通过JavaScript了解递归和记忆

javascript递归In this article, you’re going to learn how to use recursive programming, what it is, and how to optimize it for use in algorithms. We’ll be using JavaScript as our programming language of choice to understand the concept of recursion. 在本文…

[C#][正则表达式]寻找匹配的Groups的几种方法

寻找匹配的Groups的几种方法示例&#xff1a;// // 两种大方法: // MatchCollection<->Matches // Match<->Match方式 // // 第一大种&#xff1a; MatchCollection mMCollection oRegex.Matches(strHTMLContent); if(mMCollection.Count > 1) { forea…

Apollo Boost简介

With as much as we’ve gone over creating APIs with GraphQL and Prisma in previous articles, we’ve never actually applied our custom backend to a client-side app. In this article, you’ll learn how to let your user interact with your backend through queri…

成就Android英才之路

著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。作者&#xff1a;王宇龙链接&#xff1a;http://www.zhihu.com/question/19759722/answer/29213925来源&#xff1a;知乎由于工作需要大量修改framework代码, 在AOSP(Android Open Source Proj…

如何设计架构?

axing&#xff08;转载自www.Linuxaid.com.cn&#xff09;  2003年05月04日 Part 1 层 层&#xff08;layer&#xff09;这个概念在计算机领域是非常了不得的一个概念。计算机本身就体现了一种层的概念&#xff1a;系统调用层、设备驱动层、操作系统层、CPU指令集。每个层都负…