android插件化hook插件化框架总结(插件包管理 您所在的位置:网站首页 android框架结构 android插件化hook插件化框架总结(插件包管理

android插件化hook插件化框架总结(插件包管理

2023-03-04 18:33| 来源: 网络整理| 查看: 265

Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 ) 【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 ) 【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 ) 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 ) 【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 ) 【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 ) 【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )

【Android 插件化】Hook 插件化框架 ( Hook 技术 | 代理模式 | 静态代理 | 动态代理 ) 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 ) 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )

【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 ) 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 ) 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements ) 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements ) 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 ) 【Android 插件化】Hook 插件化框架 ( 创建插件应用 | 拷贝插件 APK | 初始化插件包 | 测试插件 DEX 字节码 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 ) 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 ) 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 ) 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )

【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )

【Android 插件化】Hook 插件化框架 ( 插件包资源加载 ) 【Android 插件化】Hook 插件化框架 ( 从源码角度分析加载资源流程 | Hook 点选择 | 资源冲突解决方案 ) 【Android 插件化】Hook 插件化框架 ( 使用 Hook 方式替换插件 Activity 的 mResources 成员变量 )

【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★

文章目录 Android 插件化系列文章目录前言一、项目结构及运行方法1、项目结构2、项目运行 二、宿主应用1、拷贝工具类2、自定义 Application3、宿主 Activity 界面 三、插件化框架1、反射工具类2、插件包管理器类3、Hook 操作类4、Hook AMS 代理类5、Hook Handler 代理类6、Hook Instrumentation 代理类7、占坑 Activity 四、插件应用五、博客资源

前言

本系列博客开发了一个简易 Hook 插件化框架 , 仅做学习使用 , 商业化还是使用大厂退出的成熟插件化框架 ;

源码在博客资源中 ;

一、项目结构及运行方法 1、项目结构

这是项目的结构图 ;

host 是宿主应用 Module ;

plugin 是插件应用 Module ;

lib_plugin_core 是插件化框架 , 是插件化依赖库 , 项目类型是 Android Library Module ;

2、项目运行

编译 plugin 插件应用 , 将编译后的 APK 安装包拷贝到宿主应用 host 的 " Plugin_Hook\\host\\src\\main\\assets " 目录下 ;

在 host 应用启动时 , 会将文件从 项目资源文件目录 " assets/plugin.apk " 拷贝到 " /data/user/0/com.example.plugin_hook/files/plugin.apk " Android 内置存储目录中 ;

运行时直接读取该内置文件中的插件包 , 加载 , 并显示插件包 APK 中的 Activity 界面 ;

GitHub 上的应用可以直接运行 , 我已经将 plugin 插件应用编译成 APK , 并拷贝到了 宿主应用的 assets 资源目录下 ;

注意拷贝后将 APK 插件包文件名修改为 plugin.apk ;

二、宿主应用

1、拷贝工具类

该工具类的作用是将 assets 资源文件拷贝到 Android 文件系统中 ;

package com.example.host; import android.content.Context; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class CommandUtils /** * 将 Assets 中的文件拷贝到应用内置存储区域 * @param context 上下文 * @param assetsFilePath Assets 中的文件路径 * @param appFilePath 应用内置存储 * @return */ public static boolean copyAssets2File(Context context, String assetsFilePath, String appFilePath) // 内置存储文件对象 File file = new File(appFilePath); // 确保目录存在 File filesDirectory = file.getParentFile(); if (!filesDirectory.exists()) filesDirectory.mkdirs(); // 拷贝文件 boolean ret = false; InputStream is = null; FileOutputStream fos = null; try is = context.getAssets().open(assetsFilePath); fos = new FileOutputStream(file); byte[] buffer = new byte[2048]; int n; while ((n = is.read(buffer)) != -1) fos.write(buffer, 0, n); fos.flush(); ret = true; catch (IOException e) e.printStackTrace(); finally if (null != is) try is.close(); catch (IOException e) e.printStackTrace(); if (null != fos) try fos.close(); catch (IOException e) e.printStackTrace(); return ret; public static String inputStream2String(InputStream inputStream) try BufferedReader r = new BufferedReader(new InputStreamReader(inputStream)); String str; StringBuilder sb = new StringBuilder(); while ((str = r.readLine()) != null) sb.append(str); return sb.toString(); catch (IOException e) e.printStackTrace(); return null; 2、自定义 Application

主要用于初始化插件化框架 ;

package com.example.host; import android.app.Application; import android.util.Log; import java.io.File; import kim.hsl.plugin.PluginManager; public class MyApplication extends Application private static final String TAG = "plugin_MyApplication"; /** * 插件资源, 这种方式侵入代码 , 造成开发的差异性 , 建议使用 Hook 加载插件资源 */ //private Resources pluginResources; @Override public void onCreate() super.onCreate(); // 如果已经存在文件, 先删除 , 防止拷贝过程中出错 File pluginFile = new File(getFilesDir() + "/plugin.apk"); if (pluginFile.exists()) pluginFile.delete(); // 先将 assets 中的插件包拷贝到 内置存储中 CommandUtils.copyAssets2File( this, "plugin.apk", getFilesDir() + "/plugin.apk"); // 将文件从 assets/plugin.apk 拷贝到 /data/user/0/com.example.plugin_hook/files/plugin.apk Log.i(TAG, "将文件从 assets/plugin.apk 拷贝到 " + getFilesDir() + "/plugin.apk"); // 初始化插件包 PluginManager.getInstance(this).init(); Log.i(TAG, "插件化 初始化完毕"); // 设置插件包中的资源文件, 这种方式侵入代码 , 造成开发的差异性 , 建议使用 Hook 加载插件资源 //pluginResources = PluginManager.getInstance(this).getmResources(); /* // 这种方式侵入代码 , 造成开发的差异性 , 建议使用 Hook 加载插件资源 @Override public Resources getResources() if (pluginResources != null) return pluginResources; return super.getResources(); */ 3、宿主 Activity 界面

在该 Activity 界面中 , 主要用于跳转到插件 Activity 中 ;

package com.example.host; import androidx.appcompat.app.AppCompatActivity; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MainActivity extends Activity private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "宿主应用 MainActivity onCreate"); // 反射插件包中的 com.example.plugin.MainActivity Class clazz = null; try clazz = Class.forName("com.example.plugin.MainActivity"); catch (ClassNotFoundException e) e.printStackTrace(); Method method = null; try method = clazz.getDeclaredMethod("log"); catch (NoSuchMethodException e) e.printStackTrace(); try // 执行 com.example.plugin.MainActivity 的 log 方法 method.invoke(clazz.newInstance()); catch (IllegalAccessException e) e.printStackTrace(); catch (InvocationTargetException e) e.printStackTrace(); catch (InstantiationException e) e.printStackTrace(); // 设置按钮点击事件 findViewById(R.id.button).setOnClickListener(new View.OnClickListener() @Override public void onClick(View v) // 启动插件包中的 Activity Intent pluginIntent = new Intent(); pluginIntent.setComponent(new ComponentName("com.example.plugin", "com.example.plugin.MainActivity")); pluginIntent.putExtra("isPlugin", true); startActivity(pluginIntent); ); 三、插件化框架

1、反射工具类

使用反射工具类 , 能快速开发反射相关功能 ;

package kim.hsl.plugin; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 封装反射相关逻辑的工具类 * 该封装类会维持链式调用 */ public class Reflector /** * 反射的类型 */ private Class mClass; /** * 反射针对的实例对象 * 如获取 Object 某个字段的值 */ private Object mCaller; /** * 反射的字段 */ private Field mField; /** * 反射的方法 */ private Method mMethod; /** * 反射某个类的入口方法 * * @param type 要反射的类 * @return */ public static Reflector on(Class type) Reflector reflector = new Reflector(); reflector.mClass = type; return reflector; /** * 反射某个类的入口方法 * * @param className 要反射的类名 * @return */ public static Reflector on(String className) try return on(Class.forName(className)); catch (ClassNotFoundException e) e.printStackTrace(); return null; /** * 反射某个类的入口方法 * * @param object 反射类对应的实例对象 * @return */ public static Reflector on(Object object) return on(object.getClass()).with(object); /** * 设置反射对应的实例对象 * * @param object * @return */ public Reflector with(Object object) mCaller = object; return this; /** * 创建 mClass 类型的实例对象 * @param * @return * @throws Exception */ public T newInstance() try return (T) mClass.newInstance(); catch (IllegalAccessException e) e.printStackTrace(); return null; catch (InstantiationException e) e.printStackTrace(); return null; /** * 反射类中的某个字段 * * @param name 要反射的字段名称 * @return */ public Reflector field(String name) mField = findField(name); mField.setAccessible(true); return this; /** * 查找字段名称 * 首先在本类中查找 * 如果找到直接返回字段 * 如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段 * 如果有父类 , 则在父类中查找 * 如果在父类中找到 , 返回该字段 * 如果在父类中没有找到 , 则返回空 * 如果没有父类 , 返回空 * * 尽量传具体的正确的类 , 不要传子类 * @param fieldName * @return */ private Field findField(String fieldName) try // 首先在本类中查找 , 如果找到直接返回字段 return mClass.getDeclaredField(fieldName); catch (NoSuchFieldException e) // 如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段 for (Class clazz = mClass; clazz != null; clazz = clazz.getSuperclass()) try // 如果在父类中找到 , 返回该字段 return clazz.getDeclaredField(fieldName); catch (NoSuchFieldException ex) // 如果在父类中没有找到 , 则返回空 return null; // 如果没有父类, 则返回空 return null; /** * 获取 mCaller 对象中的 mField 属性值 * * @return */ public Object get() try return mField.get(mCaller); catch (IllegalAccessException e) e.printStackTrace(); return null; /** * 设置 mCaller 对象中的 mField 属性值 * * @param value * @return 链式调用 , 返回 Reflector */ public Reflector set(Object value) try mField.set(mCaller, value); catch (IllegalAccessException e) e.printStackTrace(); return this; /** * 反射类中的某个方法 * * @param name * @param args * @return */ public Reflector method(String name, Class... args) mMethod = findMethod(name, args); mMethod.setAccessible(true); return this; /** * 根据方法名 和 参数名称 , 查找 Method 方法 * 首先在本类中查找 * 如果找到直接返回字段 * 如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段 * 如果有父类 , 则在父类中查找 * 如果在父类中找到 , 返回该字段 * 如果在父类中没有找到 , 则返回空 * 如果没有父类 , 返回空 * * 尽量传具体的正确的类 , 不要传子类 * @param name * @param args * @return */ private Method findMethod(String name, Class... args) try // 首先在本类中查找 , 如果找到直接返回方法 return mClass.getDeclaredMethod(name, args);插件化之插件service新的hook方法

android插件化hook插件化框架(加载插件包资源)(代码片段)

android插件化hook插件化框架(通过反射获取“插件包“中的element[]dexelements)(代码片段)

android插件化hook插件化框架(创建插件应用|拷贝插件apk|初始化插件包|测试插件dex字节码)(代码片段)

android插件化hook插件化框架(合并“插件包“与“宿主“中的element[]dexelements|设置合并后的element[]数组)(代码片段)

android插件化hook插件化框架(hookactivity启动流程|hook点分析)(代码片段)

android插件化hook插件化框架(使用hook方式替换插件activity的mresources成员变量)(代码片段)

android插件化hook插件化框架(从源码角度分析加载资源流程|hook点选择|资源冲突解决方案)(代码片段)

android插件化hook插件化框架(反射工具类|反射常用操作整理)(代码片段)

android插件化hook插件化框架(hookactivity启动流程|反射获取iactivitymanager对象)(代码片段)

android插件化hook插件化框架(通过反射获取“宿主“应用中的element[]dexelements)(代码片段)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有