Android插件化技术调研
一、技術背景
??????? Android的插件化技術,目前已經比較成熟,微信、淘寶、攜程、360手機助手中都應用到了插件化。插件化技術的特點是無需單獨安裝apk,即可運行,即插即用,無需升級宿主應用,減少app的更新頻率,
除此之外他還可以降低模塊耦合,按需加載,節省流量等特點。
?
二、已有框架技術對比
?????? 表1從是否支持四大組件、是否須在主manifest預注冊等多個維度對主流開源框架進行對比,從而篩選出比較符合項目的框架有VirtualAPK、RePlugin。
表1主流開源框架的對比
| 特性 | DynamicLoadApk | DynamicAPK | Small | DroidPlugin | VirtualAPK | RePlugin | ACDD/Atlas |
| 支持四大組件 | 只支持Activity | 只支持Activity | 只支持Activity | 全支持 | 全支持 | 全支持 | 全支持 |
| 組件無需在宿主manifest中預注冊 | ? | × | ? | ? | ? | ? | × |
| 插件可以依賴宿主 | ? | ? | ? | × | ? | 輕度依賴 | ? |
| 支持PendingIntent | × | × | × | ? | ? | ? | 未明確 |
| Android特性支持 | 大部分 | 大部分 | 大部分 | 幾乎全部 | 幾乎全部 | 幾乎全部 | 未明確 |
| 兼容性適配 | 一般 | 一般 | 中等 | 高 | 高 | 高 | 未明確 |
| 插件構建 | 無 | 部署aapt | Gradle插件 | 無 | Gradle插件 | Gradle插件 | 部署aapt |
| 框架輕重 | | | | 相對輕量 | 相對輕量 | 相對輕量 | 重量 |
| 支持安卓版本 | | | | | API Level 15+ | API Level 9+ | |
| 接入難度 | | | | | 中 | 易 | 難 |
| 側重階段 | | | | 運行期 | 運行期 | 運行期 | 編譯期 |
| 熱修復能力 | 無 | 無 | 無 | 無 | 無 | 無 | 有 |
| 插件安裝后可否刪除 | | | | | 不能 | 不能 | 可以 |
| 插件更新方式 | | | | | 插件獨立更新 | 插件獨立更新 | 插件及宿主須同時更新 |
??????? 對表1各插件化框架進行篩選,最后可得出VirtualAPK為最優候選框架。
??????? 以下對重點對VirtualAPK做詳細調研。
?
三、VirtualAPK
3.1 VirtualAPK主要優勢
-
功能完備: 支持幾乎所有的Android特性, 四大組件均不需要在宿主manifest中預注冊,每個組件都有完整的生命周期;
-
優秀的兼容性: 兼容市面上幾乎所有的Android手機,資源方面適配小米、Vivo、Nubia等,對未知機型采用自適應適配方案, 極少的Binder Hook且hook過程做了充分的兼容性適配,插件運行邏輯和宿主隔離,確??蚣艿娜魏螁栴}都不會影響宿主的正常運行。
-
入侵性極低: 四大組件無需繼承特定的基類,插件可以依賴宿主中的代碼和資源,通過Gradle插件來完成插件的構建,整個過程對開發者透明。
????? 如下是VirtualAPK的整體架構圖。
?
????? 詳情參見:
????? https://github.com/didi/VirtualAPK/wiki
3.2 VirtualAPK主要工作原理
????? VirtualAPK 對于插件沒有額外的約束,原生的 apk 即可作為一個插件。插件工程編譯生成 apk 后,通過宿主 App 加載,每個插件 apk 被加載后,都會在宿主中創建一個單獨的 LoadedPlugin 對象。如上圖所示,通過這些 LoadedPlugin 對象,VirtualAPK 就可以管理插件并賦予插件新的意義,使其可以像手機中安裝過的App一樣運行。
圖2 插件開發及加載過程
????? 圖3描述了LoadedPlugin的結構,LoadedPlugin包含有插件apk中定義的activities、services、
????? broadcast receivers、providers、classloader、resources等資源,LoadedPlugin實例化及加載時機如圖2所示,由PluginManager執行其loadPlugin方法將插件apk加載進dalvik。
圖3 LoadedPlugin結構
3.2.1基本原理
-
動態代理
????????? 基于JDK Proxy、InvocationHandler實現對任意java類的AOP控制。
?
-
Hook AMS\Instrumentation\IContentProvider
Hook技術基于反射和動態代理技術。
VirtualAPK通過Hook技術,從而實現對Activity、Service、ContentProvider的控制。
-
Hook AMS
Hook要點為基于動態代理技術實現ActivityManagerProxy,以實現攔截ActivityManagerService的方法調用,然后利用反射將ActivityManagerNative實例替換掉ActivityManagerNative的gDefault成員。
-
圖4 AMS Hook代碼
-
Hook Instrumentation
-
??????????????????? Hook要點為擴展Instrumentation以實現對Activity啟動過程的控制,然后使用反射將擴展
??????????????????? Instrumentation實例替換ActivityThread對象原來的Instrumentation對象。
圖5 Instrumentation Hook代碼
-
Hook IContentProvider
-
?圖6 IContentProvider Hook代碼
?
-
合并宿主和插件的ClassLoader
dalvik.system.BaseDexClassLoader內部定義了DexPathList,用于記錄去哪里加載指定的類,而DexPathList內部定義了dexElements,專門記錄已加載的dex。
對于宿主工程來說,在加載插件工程后,將插件dex插入到宿主工程的dexElements集合后面即可,在之后的運行中就可以按需加載插件中的class。
需要注意的是,插件中的類不可以和宿主重復 。
?圖 7宿主和插件Dex合并示意圖
-
合并插件和宿主的資源 重設插件資源的packageId,將插件資源和宿主資源合并
-
去除插件包對宿主的引用 構建時通過Gradle插件去除插件對宿主的代碼以及資源的引用
3.2.2四大組件的實現原理
-
Activity
采用宿主manifest中占坑的方式來繞過系統校驗,然后再加載真正的activity;
圖8描述了VirtualAPK根據launchMode定義了2(standard) + 8(singleTop) + 8(singleTask) + 8(singleInstance) = 26個SubActivity坑.
圖 8 CoreLibrary工程的AndoidManifest
?????? 圖9描述了啟動插件apk中activity的主要過程,也是VirtualAPK插件無需在AndroidManifest預注冊的原理。該原理是VirtualAPK預先在AndroidManifest注冊一些StubActivity,這些StubActivity并沒有實際的代碼實現,在之后啟動插件Activity時,VirtualAPK將插件Activity改名為StubActivity,在繞過Android對啟動插件Activity的合法校驗后,再將StubActivity改回原來的Activity名稱。
?????? 該過程有兩個關鍵點:
?????? 1) 將插件Activity轉換為StubActivity;
?????????? 該階段的作用是繞過Android對啟動Activity的限制:Activity必須先在AndroidManifest注冊,否則不能被startActivity。具體實現為利用hook的VAInstrumentation攔截Instrumentation的execStartActivity方法,并在該方法內將待啟動的插件Activity名稱改 為StubActivity。
?????? 2) 將StubActivity還原為插件Activity。
?????????? 此階段的作用是繼1)階段繞過系統對插件Activity的合法校驗后,將StubActivity名稱改回原來的名稱,以使得在Instrumentation.newActivity時實例并啟動正確的目標Activity。
圖9插件Activity啟動過程
-
Service 動態代理AMS,攔截service相關的請求,將其中轉給Service Runtime去處理,Service Runtime會接管系統的所有操作;
????????? 插件Service的啟動/關閉基于被Hook的AMS,VirtualAPK在攔截到start/bind/stop/unbind Service的調用后,會執行ActivityManagerProxy的invoke方法,之后控制流程和數據會轉交給ServiceDelegate對象,之后ServiceDeletegate會判斷待啟動的Service是本地服務還是遠程服務,如果是本地服務,VirtualAPK會反射調用Service相應生命周期的方法;如果是遠程服務,VirtualAPK先將目標插件apk加載進來,然后再反射調用目標Service的生命周期方法。
?
圖10插件Service啟動過程
-
Receiver 將插件中靜態注冊的receiver重新注冊一遍;
-
ContentProvider 動態代理IContentProvider,攔截provider相關的請求,將其中轉給Provider Runtime去處理,Provider Runtime會接管系統的所有操作。
?
四、VirtualApk框架主要問題調研
4.1 VirtualApk是否支持混淆
結論:VirtualApk主工程支持混淆,子工程也支持混淆
4.2、調研以下問題:
4.2.1 插件下載后,需不需要重啟app才能完成加載?
結論:插件下載后不需要App重啟即可生效,但插件升級后需重啟app.
1) VirtualApk
github項目描述原話:
VirtualApk can dynamically load and run an APK file(we call it LoadedPlugin) seamless as an installed application.
說明插件下載后不需重啟app即可生效運行;
2) 反證法思路:VirtualApk是當下最流行的插件化框架,如果其在插件下載后需要app重啟,那么該框架肯定不會被業界認可;
3) 實踐證實插件下載后不需app重啟即可生效,但插件更新后需app重啟方可生效。
嘗試PluginManager卸載再裝載組件的思路,實驗結果未能成功自動更新升級后的組件。
4.3插件中和主app如果包含同樣的庫,執行中會不會遇到問題?
結論:所查閱文獻明確說明 插件不能包含有主工程的代碼,但插件工程在編譯時應該可以使用主工程代碼協助編譯,只是編譯完成后就不能有主工程代碼。
經實際編碼驗證,如果插件和主app包含同樣的代碼,以主app代碼為準。
參考文獻:
https://blog.csdn.net/u012439416/article/details/76595643
https://juejin.im/entry/59e8618cf265da43143fcf68
4.4不用反射的方法,能不能讓宿主直接調用插件中的類和方法?
結論:Java類經ClassLoader加載到JVM后,有反射和接口調用兩種方式
Class A = Class.forName("com.some.class.A");
//反射方式
Method?method?=?A.getDeclaredMethod(...);
method.invoke(null,?...);
//接口方式
InterfaceA objA = (InterfaceA) A.newInstance(...);
objA.interfaceMethod();
InterfaceA定義:?
interface?InterfaceA?{
void interfaceMethod();
}
五、VirtualAPK驗證
5.1 宿主工程直接調用插件工程的四大組件宿主工程調用插件工程的Activity/Service, 插件工程內部再調用自己或其他插件的四大組件表2 VirtualAPK實驗結果| 方式 | Activity | Service | BroadcastReceiver | ContentProvider |
| 宿主工程直接調用插件工程 | ? | × | ? | ? |
| 宿主工程間接調用插件工程 | ? | × | ? | ? |
| 序號 | 宿主工程是否混淆 | 插件工程是否混淆 | 運行效果 |
| 1 | 混淆 | 混淆 | ? |
| 2 | 混淆 | 未混淆 | × |
| 3 | 未混淆 | 混淆 | ? |
| 4 | 未混淆 | 未混淆 | ? |
6、總結
???????? 根據是否支持四大組件、是否需在宿主工程manifest預注冊、插件工程是否可依賴宿主工程等指標,對表1各插件化框架進行篩選,最后可得出VirtualAPK為最優候選框架。但經過實際編碼驗證,四大組件除Service外都可被VirtualAPK支持。
7、參考文章
- Android 360開源全面插件化框架RePlugin實戰
- ACDD使用教程
- Android插件化框架
- OpenAtlas之4四 資源分布結構解析
- Android OpenAtlas初識
-
Android插件化開發之OpenAtlas初體驗
??????????? https://www.aliyun.com/jiaocheng/47101.html?spm=5176.100033.2.10.LuYTOz
-
Android插件化開發之OpenAtlas中四大組件與Application功能的驗證https://blog.csdn.net/sbsujjbcy/article/details/47952269
-
Atlas、VirtualAPK、RePlugin三者的體驗感受
????????? https://www.jianshu.com/p/ceded2da7847
-
Android插件化:從入門到放棄
????????? http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up
?
?
?
?
?
轉載于:https://www.cnblogs.com/tgltt/p/9542193.html
總結
以上是生活随笔為你收集整理的Android插件化技术调研的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Daily Scrum】12-08
- 下一篇: Android 通信 EventBus