【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )(三)

简介: 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )(三)

二、完整代码示例


package kim.hsl.plugin;
import android.content.Context;
import java.lang.reflect.Field;
import dalvik.system.DexClassLoader;
/**
 * 使用 Hook 实现的插件使用入口
 *  1. 加载插件包中的字节码
 *  2. 直接通过 hook 技术, 钩住系统的 Activity 启动流程实现
 *      ① Activity 对象创建之前 , 要做很多初始化操作 , 先在 ActivityRecord 中加载 Activity 信息
 *          如果修改了该信息 , 将要跳转的 Activity 信息修改为插件包中的 Activity
 *          原来的 Activity 只用于占位 , 用于欺骗 Android 系统
 *      ② 使用 hook 技术 , 加载插件包 apk 中的 Activity
 *      ③ 实现跳转的 Activity ( 插件包中的 )
 *  3. 解决 Resources 资源冲突问题
 *  ( 使用上述 hook 插件化 , 可以不用考虑 Activity 的声明周期问题 )
 *
 *  插件包中的 Activity 是通过正规流程 , 由 AMS 进行创建并加载的
 *      但是该 Activity 并没有在 AndroidManifest.xml 清单文件中注册
 *      这里需要一个已经在清单文件注册的 Activity 欺骗系统
 *
 *  插装式插件化 是通过代理 Activity , 将插件包加载的字节码 Class 作为一个普通的 Java 类
 *      该普通的 Java 类有所有的 Activity 的业务逻辑
 *      该 Activity 的声明周期 , 由代理 Activity 执行相关的生命周期方法
 *  hook 插件化 : hook 插件化直接钩住系统中 Activity 启动流程的某个点
 *      使用插件包中的 Activity 替换占位的 Activity
 */
public class PluginManager {
    /**
     * 上下文
     */
    private Context mBase;
    /**
     * 单例
     */
    private static PluginManager instance;
    public static PluginManager getInstance(Context context) {
        if (instance == null) {
            instance = new PluginManager(context);
        }
        return instance;
    }
    private PluginManager(Context context) {
        this.mBase = context;
    }
    /**
     * Application 启动后 , 调用该方法初始化插件化环境
     *  加载插件包中的字节码
     */
    private void init() {
        // 加载 apk 文件
        loadApk();
    }
    private void loadApk() {
        // 插件包的绝对路径 ,  /data/data/< package name >/files/
        String apkPath = mBase.getFilesDir().getAbsolutePath() + "plugin.apk";
        // 加载插件包后产生的缓存文件路径
        // /data/data/< package name >/app_plugin_cache/
        String cachePath =
                mBase.getDir("plugin_cache", Context.MODE_PRIVATE).getAbsolutePath();
        // 创建类加载器
        DexClassLoader plugin_dexClassLoader =
                new DexClassLoader(
                        apkPath,                // 插件包路径
                        cachePath,              // 插件包加载时产生的缓存路径
                        null,   // 库的搜索路径, 可以设置为空
                        mBase.getClassLoader()  // 父加载器, PathClassLoader
                );
        // 1. 反射 " 插件包 " 应用的 dexElement
        // 执行步骤 :
        // ① 反射获取 BaseDexClassLoader.class
        // ② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段
        // ③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象
        // ④ 反射获取 DexPathList.class
        // ⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象
        // ⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象
        // ① 反射获取 BaseDexClassLoader.class
        // 通过反射获取插件包中的 dexElements
        // 这种类加载是合并类加载 , 将所有的 Dex 文件 , 加入到应用的 dex 文件集合中
        //  可参考 dex 加固 , 热修复 , 插装式插件化 的实现步骤
        // 反射出 BaseDexClassLoader 类 , PathClassLoader 和 DexClassLoader
        //  都是 BaseDexClassLoader 的子类
        // 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
        Class<?> baseDexClassLoaderClass = null;
        try {
            baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        // ② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段
        Field plugin_pathListField = null;
        try {
            plugin_pathListField = baseDexClassLoaderClass.getDeclaredField("pathList");
            // 设置属性的可见性
            plugin_pathListField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        // ③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象
        // 根据 Field 字段获取 成员变量
        //  DexClassLoader 继承了 BaseDexClassLoader, 因此其内部肯定有
        //  private final DexPathList pathList 成员变量
        Object plugin_pathListObject = null;
        try {
            plugin_pathListObject = plugin_pathListField.get(plugin_dexClassLoader);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // ④ 获取 DexPathList.class
        // DexPathList 类中有 private Element[] dexElements 成员变量
        // 通过反射获取该成员变量
        // 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
        // 获取 DexPathList pathList 成员变量的字节码类型 ( 也可以通过反射获得 )
        // 获取的是 DexPathList.class
        Class<?> plugin_dexPathListClass = plugin_pathListObject.getClass();
        // ⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象
        Field plugin_dexElementsField = null;
        try {
            plugin_dexElementsField = plugin_dexPathListClass.getDeclaredField("dexElements");
            // 设置属性的可见性
            plugin_dexElementsField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        // ⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象
        Object plugin_dexElementsObject = null;
        try {
            plugin_dexElementsObject = plugin_dexElementsField.get(plugin_pathListObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}


目录
相关文章
|
1月前
|
算法 JavaScript Android开发
|
1月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
2月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
139 1
|
3月前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
440 3
|
Android开发
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )(三)
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )(三)
173 0
|
安全 Java Android开发
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )(一)
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )(一)
211 0
|
Java Android开发
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )(二)
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )(二)
136 0
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
23天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
47 19
|
23天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
50 14