日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )

發布時間:2025/6/17 Android 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 ) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 一、合并兩個 Element[] dexElements
  • 二、 完整修復包加載工具類
  • 三、 源碼資源





一、合并兩個 Element[] dexElements



在 【Android 熱修復】熱修復原理 ( 加載 Dex 文件到內存中 | DexClassLoader | PathClassLoader | 反射 Element[] dexElements ) 博客中已經將 系統加載的 Dex 文件對應的 Element[] dexElements 通過 PathClassLoader 類加載器獲取到了 , 同時修復包對應 Dex 文件 Element[] dexElements 通過 DexClassLoader 類加載器獲取到了 ;

下面開始將修復包對應的 Element[] dexElements 合并到系統 PathClassLoader 中的 Element[] dexElements 數組中 ;


在 【Android 熱修復】熱修復原理 ( 加載 Dex 文件到內存中 | DexClassLoader | PathClassLoader | 反射 Element[] dexElements ) 博客中

將系統 PathClassLoader pathClassLoader 的 DexPathList pathList 對象的 Element[] dexElements 成員systemDexElementsObject

自己在程序中的 DexClassLoader dexClassLoader 的 DexPathList pathList 對象的 Element[] dexElements 成員myDexElementsObject

進行融合 , 將 myDexElementsObject 插入到 systemDexElementsObject ;


首先要獲取 Dex 數組 , 但是 Element 類型無法引用 , 不是公開的 ;

先獲取 Element 類型 , 調用對象的 .getClass().getComponentType() 獲取 ;

// 獲取 Dex 數組 , Element 類型無法引用 , 不是公開的 // 首先獲取 Element 類型 // systemDexElementsObject Class<?> elementClass = systemDexElementsObject.getClass().getComponentType();

獲取兩個 Element[] dexElements 數組的成員個數 ;

// 獲取兩個 Element[] dexElements 數組的成員個數 // 系統中的 PathClassLoader 中的 Element[] dexElements 數組大小 int systemDexCount = Array.getLength(systemDexElementsObject); // 本應用中的 DexClassLoader 中的 Element[] dexElements 數組大小 int myDexCount = Array.getLength(myDexElementsObject);

使用 Array.newInstance 重新創建一個數組, 數組的長度是兩個數組之和 ;

// 重新創建一個數組 // 類型 : Class<?> elementClass // 長度 : systemDexCount + myDexCount Object elementArray =Array.newInstance(elementClass, systemDexCount + myDexCount);

填充創建的數組 , 這里特別注意 , 數組中的元素的順序很重要 , 一定要先放置修復包中的數組元素 , 然后放置應用自帶的 Dex 數組內容 , 這個順序一定不能亂 ;

// 填充數組內容, 這里特別注意 , 數組中的元素的順序很重要 , // 同樣類型的類 , 在多個 Dex 都存在 , 如果在前面的 Dex 中查找到了 , 就不再向后查找了 // 修復包的 Dex 要放在最前面 , 這樣才能起到修復作用// 先放置修復包 Dex for(int i = 0; i < myDexCount; i ++){// 獲取 myDexElementsObject 數組中的第 i 個元素// 放置到 elementArray 數組中的第 i 個元素位置Array.set(elementArray, i,Array.get(myDexElementsObject, i)); }// 再放置系統 Dex for(int i = 0; i < systemDexCount; i ++){// 獲取 systemDexElementsObject 數組中的第 i 個元素// 放置到 elementArray 數組中的第 i + myDexCount 個元素位置Array.set(elementArray,i + myDexCount,Array.get(systemDexElementsObject, i)); }

最后 , 通過反射方法 , 將合并后的 elementArray 數組放置到 PathClassLoader 中的 Element[] dexElements 中 ;

// 通過反射方法 // 將合并后的 elementArray 數組放置到 // PathClassLoader 中的 Element[] dexElements 中 systemDexElementsField.set(systemPathListObject, elementArray);

注意 : 此時熱修復還不能生效 , 需要進一步進行分包操作才可以 ;





二、 完整修復包加載工具類



package kim.hsl.hotfix;import android.content.Context; import android.util.Log;import java.io.File; import java.lang.reflect.Array; import java.lang.reflect.Field;import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader;public class FixDexUtils {/*** 加載 Dex 文件* @param context*/public static void loadDex(Context context){// 修復包可能有多個, 如先后進行了多次修復 , 存在多個修復包 Dex 文件// 這些 Dex 文件按照時間順序進行放置// 之前已經將 SD 卡中的 /storage/emulated/0/update.dex 文件拷貝到了// 原應用內置存儲空間 /data/user/0/kim.hsl.hotfix/app_odex/update.dex// /data/user/0/kim.hsl.hotfix/app_odex/ 目錄文件File filesDir = context.getDir("odex", Context.MODE_PRIVATE);// 獲取 /data/user/0/kim.hsl.hotfix/app_odex/ 目錄下的所有文件File[] listFiles = filesDir.listFiles();// 緩存 odex 文件的目錄 , 將 dex 優化為 odex 文件String optimizedDir = filesDir.getAbsolutePath() + File.separator + "cache_odex";// 過濾文件, 系統打包都是 classes.dex , classes1.dex , classes2.dex 等文件// 上傳的更新包 update.dex 以 .dex 為結尾// 以上面兩個條件作為過濾的依據for (File file : listFiles){if (file.getAbsolutePath().startsWith("classes") ||file.getAbsolutePath().endsWith(".dex")){// 將 dex 文件加載到內存中// 該 DexClassLoader 是 BaseDexClassLoader 的子類// BaseDexClassLoader 中有 DexPathList pathList 成員// 構造該類時 , 會自動將 dex 文件進行優化為 odex , 然后加載到上述 DexPathList pathList 中//// 參數一 : Dex 文件路徑// 參數二 : 緩存路徑, 指的是緩存 Odex 文件的目錄// 參數三 : Dex 中的 lib 庫路徑, 可以設置 null// 參數四 : 上下文的 ClassLoaderDexClassLoader dexClassLoader = new DexClassLoader(file.getAbsolutePath(),optimizedDir,null,context.getClassLoader());// 該 PathClassLoader 是用于加載查找 Android 應用所有 dex 文件的類加載器// 將上面獲取的 dexClassLoader 中的 DexPathList pathList// 插入到 PathClassLoader 中的 DexPathList pathList 成員中PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();// BaseDexClassLoader 中的 DexPathList pathList 是 private 私有的// 無法直接獲取// 需要使用反射機制獲取該 Dex 數組// 拿到 PathClassLoader (繼承 BaseDexClassLoader 類) 對象后// 先使用反射機制獲取 private final DexPathList pathList 成員// 然后再次通過反射 , 獲取 DexPathList 中的 private final Element[] dexElements 成員try {// 加載系統的 Element[] dexElements ---------------------------------------------// 反射獲取 BaseDexClassLoader 類對象Class systemBaseDexClassLoaderClass =Class.forName("dalvik.system.BaseDexClassLoader");// 反射獲取 BaseDexClassLoader 中的 private final DexPathList pathList 字段Field systemPathListField =systemBaseDexClassLoaderClass.getDeclaredField("pathList");// 由于是私有成員字段 , 需要設置可訪問性systemPathListField.setAccessible(true);// 獲取系統的 PathClassLoader pathClassLoader 對象的// private final DexPathList pathList 成員Object systemPathListObject = systemPathListField.get(pathClassLoader);// 獲取 DexPathList 類Class systemPathListClass = systemPathListObject.getClass();// 獲取 DexPathList 類中的 private final Element[] dexElements 成員字段Field systemDexElementsField =systemPathListClass.getDeclaredField("dexElements");// 由于是私有成員字段 , 需要設置可訪問性systemDexElementsField.setAccessible(true);// 獲取 DexPathList pathList 對象的 Element[] dexElements 成員Object systemDexElementsObject =systemDexElementsField.get(systemPathListObject);// 系統的 Element[] dexElements 加載完畢-----------------------------------------// 上述反射的是系統的 PathClassLoader 的對象// 下面開始反射在本次循環方法中加載的 DexClassLoader dexClassLoader// 加載自己的 Element[] dexElements ---------------------------------------------// 反射獲取 BaseDexClassLoader 類對象Class myBaseDexClassLoaderClass =Class.forName("dalvik.system.BaseDexClassLoader");// 反射獲取 BaseDexClassLoader 中的 private final DexPathList pathList 字段Field myPathListField =myBaseDexClassLoaderClass.getDeclaredField("pathList");// 由于是私有成員字段 , 需要設置可訪問性myPathListField.setAccessible(true);// 獲取系統的 PathClassLoader pathClassLoader 對象的// private final DexPathList pathList 成員Object myPathListObject = myPathListField.get(dexClassLoader);// 獲取 DexPathList 類Class myPathListClass = myPathListObject.getClass();// 獲取 DexPathList 類中的 private final Element[] dexElements 成員字段Field myDexElementsField =myPathListClass.getDeclaredField("dexElements");// 由于是私有成員字段 , 需要設置可訪問性myDexElementsField.setAccessible(true);// 獲取 DexPathList pathList 對象的 Element[] dexElements 成員Object myDexElementsObject = myDexElementsField.get(myPathListObject);// 自己的 Element[] dexElements 加載完畢-----------------------------------------// 將系統 PathClassLoader pathClassLoader 的// DexPathList pathList 對象的 Element[] dexElements 成員// systemDexElementsObject// 與// 自己在程序中的 DexClassLoader dexClassLoader 的// DexPathList pathList 對象的 Element[] dexElements 成員// myDexElementsObject// 進行融合// 將 myDexElementsObject 插入到 systemDexElementsObject// 獲取 Dex 數組 , Element 類型無法引用 , 不是公開的// 首先獲取 Element 類型// systemDexElementsObjectClass<?> elementClass = systemDexElementsObject.getClass().getComponentType();// 獲取兩個 Element[] dexElements 數組的成員個數// 系統中的 PathClassLoader 中的 Element[] dexElements 數組大小int systemDexCount = Array.getLength(systemDexElementsObject);// 本應用中的 DexClassLoader 中的 Element[] dexElements 數組大小int myDexCount = Array.getLength(myDexElementsObject);Log.i("TAG", "systemDexCount = " + systemDexCount + " , myDexCount = " + myDexCount);// 重新創建一個數組// 類型 : Class<?> elementClass// 長度 : systemDexCount + myDexCountObject elementArray =Array.newInstance(elementClass, systemDexCount + myDexCount);// 填充數組內容, 這里特別注意 , 數組中的元素的順序很重要 ,// 同樣類型的類 , 在多個 Dex 都存在 , 如果在前面的 Dex 中查找到了 , 就不再向后查找了// 修復包的 Dex 要放在最前面 , 這樣才能起到修復作用// 先放置修復包 Dexfor(int i = 0; i < myDexCount; i ++){// 獲取 myDexElementsObject 數組中的第 i 個元素// 放置到 elementArray 數組中的第 i 個元素位置Array.set(elementArray, i,Array.get(myDexElementsObject, i));}// 再放置系統 Dexfor(int i = 0; i < systemDexCount; i ++){// 獲取 systemDexElementsObject 數組中的第 i 個元素// 放置到 elementArray 數組中的第 i + myDexCount 個元素位置Array.set(elementArray,i + myDexCount,Array.get(systemDexElementsObject, i));}// 通過反射方法// 將合并后的 elementArray 數組放置到// PathClassLoader 中的 Element[] dexElements 中systemDexElementsField.set(systemPathListObject, elementArray);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}} }



三、 源碼資源



源碼資源 :

  • GitHub 地址 : https://github.com/han1202012/HotFix
  • CSDN 源碼快照 : 到下一篇博客下載 , 該快照目前還跑不起來 ;

注意 : 此時熱修復還不能生效 , 需要進一步進行分包操作才可以 ;

總結

以上是生活随笔為你收集整理的【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。