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 插件化原理
- 二、插件化依賴庫創建
- 三、插件包管理
- 四、插件包管理完整代碼示例
- 五、博客資源
前言
前 2 2 2 篇博客 【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 一 | Activity 行程相關原始碼 ) , 【Android 插件化】Hook 插件化框架 ( 從 Hook 應用角度分析 Activity 啟動流程 二 | AMS 行程相關原始碼 | 主行程相關原始碼 ) 中 , 分析了從 Activity 呼叫 startActivity 啟動另一個 Activity 的底層原始碼流程 , 涉及到了 2 2 2 個行程 , 一個是本應用的主執行緒所在的行程 , 一個是 ActivityManagerService 行程 ;
本博客中開始對 Activity 啟動程序進行 Hook 操作 , 基于 Android 9 9 9 , API 28 28 28 版本 , 這里要注意 , 不同的 API 版本底層原始碼邏輯不同 , Hook 點以及 Hook 方式也不同 ;
目前的主流插件化框架都已經兼容到了 Android 10 10 10 版本 ;
一、hook 插件化原理
使用 Hook 實作的插件化原理如下 : 通過以下 3 3 3 個步驟實作插件化 ;
1. 加載插件包中的位元組碼
2. hook 技術 : 直接通過 hook 技術, 鉤住系統的 Activity 啟動流程實作
① Activity 物件創建之前 , 要做很多初始化操作 , 先在 ActivityRecord 中加載 Activity 資訊 , 如果修改了該資訊 , 將要跳轉的 Activity 資訊修改為插件包中的 Activity , 原來的 Activity 只用于占位 , 用于欺騙 Android 系統 ;
② 使用 hook 技術 , 加載插件包 apk 中的 Activity
③ 實作跳轉的 Activity ( 插件包中的 )
3. 資源加載 : 主要是解決 Resources 資源沖突問題 ;
( 使用上述 hook 插件化 , 可以不用考慮 Activity 的生命周期問題 )
占位 Activity : 插件包中的 Activity 是通過正規流程 , 由 AMS 進行創建并加載的 , 但是 該 Activity 并沒有在 AndroidManifest.xml 清單檔案中注冊 , 這里需要一個已經在清單檔案注冊的 Activity 欺騙系統 ;
插裝式插件化 : 是通過代理 Activity , 將 插件包加載的 位元組碼 Class 類 中 對應的 Activity 類作為一個普通的 Java 類 , 該普通的 Java 類有所有的 Activity 的業務邏輯 , 該 Activity 的生命周期 , 由代理 Activity 執行相關的生命周期方法
hook 插件化 : hook 插件化直接鉤住系統中 Activity 啟動流程的某個點
二、插件化依賴庫創建
hook 插件化依賴庫是 Android 依賴庫 ( Android Library Module ) ;
創建插件化的核心依賴庫 :

通過該 lib_plugin_core 依賴庫 , 實作插件化相關功能 ;

在其中創建插件化的核心管理類 PluginManager , 用于管理插件相關內容 ;

三、插件包管理
插件包目錄 : 將插件包放在 /data/data/< package name >/files/ 目錄中 ;
// 插件包的絕對路徑 , /data/data/< package name >/files/
String apkPath = mBase.getFilesDir().getAbsolutePath() + "plugin.apk";
插件包快取目錄 : 同時設定 , 加載插件包中產生的快取檔案路徑是 /data/data/< package name >/app_plugin_cache/ 目錄 ;
// 加載插件包后產生的快取檔案路徑
// /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
);
四、插件包管理完整代碼示例
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
);
}
}
五、博客資源
博客資源 :
- GitHub : https://github.com/han1202012/Plugin_Hook
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/291900.html
標籤:其他
