[TOC]
# 插件化實現
## 類加載
### java 中的 ClassLoader
BootstrapClassLoader
負責加載 JVM 運行時的核心類,比如?JAVA\_HOME/lib/rt.jar?等等。
ExtensionClassLoader
負責加載 JVM 的擴展類,比如?JAVA\_HOME/lib/ext?下面的 jar 包。
AppClassLoader
負責加載 classpath 里的 jar 包和目錄。
### android 中的 ClassLoader
BootClassLoader <- PathClassLoader
在這里,我們統稱 dex 文件,包含 dex 的 apk 文件以及 jar 文件為 dex 文件?PathClassLoader?用來加載系統類和應用程序類,可以加載已經安裝的 apk 目錄下的 dex 文件。
DexClassLoader?用來加載 dex 文件,可以從存儲空間加載 dex 文件。
我們在插件化中一般使用的是?DexClassLoader。
~~~
//?從?assets?中拿出插件?apk?放到內部存儲空間
private?fun?extractPlugin()?{
????var?inputStream?=?assets.open("plugin.apk")
????File(filesDir.absolutePath,?"plugin.apk").writeBytes(inputStream.readBytes())
}
private?fun?init()?{
????extractPlugin()
????pluginPath?=?File(filesDir.absolutePath,?"plugin.apk").absolutePath
????nativeLibDir?=?File(filesDir,?"pluginlib").absolutePath
????dexOutPath?=?File(filesDir,?"dexout").absolutePath
????//?生成?DexClassLoader?用來加載插件類
//pluginPath?是需要加載的?dex / apk / jar?文件路徑。
//dexOutPath?是 dex 優化后存放的位置,在 ART 上,會執行 oat 對 dex 進行優化,生成機器碼,這里就是存放優化后的 odex 文件的位置。
//librarySearchPath?是 native 依賴的位置。
parent?就是父類加載器,默認會先從 parent 加載對應的
????pluginClassLoader?=?DexClassLoader(pluginPath,?dexOutPath,?nativeLibDir,?this::class.java.classLoader)
}
~~~
### 雙親委派
每一個 ClassLoader 中都有一個 parent 對象,代表的是父類加載器,在加載一個類的時候,會先使用父類加載器去加載,如果在父類加載器中沒有找到,自己再進行加載,如果 parent 為空,那么就用系統類加載器來加載。
## activity的hook
方法1、我們手動去調用插件 Activity 的生命周期。
方法2、欺騙系統,讓系統以為 Activity 是注冊在 Manifest 中的。
| 現方法 | 優點 | 缺點 |
| --- | --- | --- |
| 手動調用 | 1\. 比較穩定,不需要 hook 系統實現 2. 實現相對簡單,不需要對系統內部實現做過多了解 | 通過反射效率太低,通過接口需要實現的方法數量很多 |
| hook 系統 | 1\. 不需要實現大量接口方法 2. 由于最終還是交給系統去處理,各種處理相對比較完整 | 1\. 需要適配不同的系統及設備 2. 對開發者要求比較高,需要對系統實現有深入的了解 |
#### hook系統(Instrumentation)

有兩個關鍵點,execStartActivity?和?newActivity。
execStartActivity?是在啟動 Activity 的時候必經的一個過程,這時還沒有到達 AMS,所以,在這里把 Activity 替換成宿主中已經注冊的?StubActivity,這樣 AMS 在檢測 Activity 的時候就認為已經注冊過了。newActivity?是創建 Activity 實例,這里要返回真正需要運行的插件 Activity,這樣后面系統就會基于這個 Activity 實例來進行對應的生命周期的調用。
資源
## shadow實現
### Manager VS Loader VS Container
Manager的功能就是管理插件,包括插件的下載邏輯、入口邏輯,預加載邏輯等.反正就是一切還沒有進入到Loader之前的所有事情。
Loader就是負責加載插件Activity,然后實現插件Activity的生命周期等功能的那部分核心邏輯了。
Container就是那些注冊在宿主AndroidManifest中的代理殼子。由于Activity的創建是系統根據Activity的名字直接通過宿主的PathClassLoader構造的,所以這些Activity必須打包在宿主中才能處于PathClassLoader,才能被系統找到。所以Container是不能放到Loader中,通過動態加載的一般方法加載的。因為前面提到的一般方法都是要new一個新的ClassLoader加載動態實現的。
### ClassLoader
我們可以通過修改ClassLoader的parent,為ClassLoader新增一個parent。將原本的
~~~
BootClassLoader <- PathClassLoader
~~~
結構變為
~~~
BootClassLoader <- DexClassLoader <- PathClassLoader
~~~
,插入的DexClassLoader加載了ContainerActivity就可以使得系統在向PathClassLoader查找ContainerActivity時能夠正確找到實現。
### Activity
核心:加入的ShadowActivity就是這個中間層。通過這個中間層讓Android系統看不到插件,也讓插件看不到Android系統。
技術:字節碼插樁
# 參考資料
[Shadow源碼解析](https://github.com/ChenSiLiang/android-toy/blob/master/Shadow%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90%E7%AC%94%E8%AE%B0/Shadow%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90.md)
[Android 插件化的今生前世大揭秘](https://mp.weixin.qq.com/s/EuCqudpPnBRidtmZBocNYg)
- Android
- 四大組件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介紹
- MessageQueue詳細
- 啟動流程
- 系統啟動流程
- 應用啟動流程
- Activity啟動流程
- View
- view繪制
- view事件傳遞
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大數據
- Binder小結
- Android組件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 遷移與修復
- Sqlite內核
- Sqlite優化v2
- sqlite索引
- sqlite之wal
- sqlite之鎖機制
- 網絡
- 基礎
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP進化圖
- HTTP小結
- 實踐
- 網絡優化
- Json
- ProtoBuffer
- 斷點續傳
- 性能
- 卡頓
- 卡頓監控
- ANR
- ANR監控
- 內存
- 內存問題與優化
- 圖片內存優化
- 線下內存監控
- 線上內存監控
- 啟動優化
- 死鎖監控
- 崩潰監控
- 包體積優化
- UI渲染優化
- UI常規優化
- I/O監控
- 電量監控
- 第三方框架
- 網絡框架
- Volley
- Okhttp
- 網絡框架n問
- OkHttp原理N問
- 設計模式
- EventBus
- Rxjava
- 圖片
- ImageWoker
- Gilde的優化
- APT
- 依賴注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 協程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 運行期Java-hook技術
- 編譯期hook
- ASM
- Transform增量編譯
- 運行期Native-hook技術
- 熱修復
- 插件化
- AAB
- Shadow
- 虛擬機
- 其他
- UI自動化
- JavaParser
- Android Line
- 編譯
- 疑難雜癥
- Android11滑動異常
- 方案
- 工業化
- 模塊化
- 隱私合規
- 動態化
- 項目管理
- 業務啟動優化
- 業務架構設計
- 性能優化case
- 性能優化-排查思路
- 性能優化-現有方案
- 登錄
- 搜索
- C++
- NDK入門
- 跨平臺
- H5
- Flutter
- Flutter 性能優化
- 數據跨平臺