Android插件化开发之动态加载的类型
https://segmentfault.com/a/1190000005113493
基本信息
-
Author:kaedea
-
GitHub:android-dynamical-loading
現在網絡上有許多關于動態加載的介紹的文章,談及的關鍵詞匯有動態加載、插件化、熱部署、熱修復等,對于一些剛接觸這方面開發技術的人來說,可能容易混淆。
雖然我在動態加載系列的文章中或多或少有談到這些概念的區別,但是我覺得認識這些區別對于使用動態加載技術還是挺重要的,所以特別開這個新的文章進行分析。
動態加載的類型
無論是插件化、熱部署還是熱修復,這些技術的根源都可是說是動態加載,這也是我把“動態加載”作為這個系列文章主題的原因。
動態加載,就是在程序運行時,加載外部的可執行文件并運行。這里的運行時就是指應用冷啟動并開始工作后;外部可以是可以是SD卡,可以是data目錄,也可以是jniLib目錄,這些可執行文件是沒有隨著應用一起編譯的。
Android的動態加載按照工作機制的不同,可以分為虛擬機層動態加載和Native層動態加載兩大類。
運行在虛擬機
簡單來說就是只用JAVA代碼搞定的類型。
基于虛擬機的動態加載技術的核心是類加載器ClassLoader,通過它我們能夠加載一些新的類,這種方式也是目前大部分技術文章談到的加載方式。其中,根據ClassLoader使用方式的不同,又演變出“熱部署”、“插件化”、“熱修復”等技術。
熱部署
加載外部可執行文件的ClassLoader實例與原APP的ClassLoader實例是互相獨立的(不在同一棵代理樹上),加載進來的新的類與原APP(宿主)里存在的類互相獨立,根據Java對類的定義,因為這些類的ClassLoader不同,所以他們即便包名和類名一致,或者有繼承關系,他們也屬于不懂的類。所以以這種方式加載進來的類與原有的類不能互通,不能污染宿主原有的類,適合用來動態加載一些獨立的業務,比如一些推廣的游戲,在宿主上提供一個入口,用戶不需要安裝游戲就能運行。因為這種方式起到不用安裝就能部署游戲的作用,所以稱為熱部署。
插件化
加載外部可執行文件的ClassLoader實例與宿主的ClassLoader實例不是互相獨立的,用宿主的ClassLoader加載過的類就無法從外部可執行文件中再次加載,它們可以共用一個公共庫,習慣上把外部可執行文件稱為插件。插件里可以存放公共庫里一些借口的實現類,可以有一些新的Activity或者Service等組件,可以把一些宿主里的業務挪到插件中,插件可以自主升級,不用隨著宿主APP發版。
熱修復
在使用插件化技術的同時,也可以使用插件中的新的類來替換宿主同名的類,這樣就能修復宿主中原有的類存在的BUG。相比插件化,熱修復因為不需要考慮組件和res資源的問題,所以相對簡單得許多,要保證插件種新的類的加載要在加載宿主中原有類的之前。
拆分DEX
相信大家都知道打包DEX時65536方法數超標問題,也就是一個DEX只能有65536個方法,因此有了multi-dex的解決方案,把本來只有一個的DEX,拆分成復數以上的DEX,運行時挨個加載進來,這其實也算是一種動態加載,只不過實現過程對開發者是透明的。
除此之外,還有另一種拆分DEX是用于減少冷啟動的時間的。冷啟動是指應用第一次從用戶點擊到完成初始化工作的全部過程。隨著現在APP的體積不斷增長,一些APP的DEX文件十分龐大,APP在啟動的時候,單單加載所有的DEX文件就需要非常多的耗時,所以用戶點擊APP的時候會有一個明顯的卡頓過程。因此有一種拆分DEX的方案是“拆分一個啟動閃屏用的DEX,里面只存放啟動閃屏界面需要用到的類,因此非常小,其他類放到其他DEX里面”,啟動的時候因為只需要加載閃屏的DEX,所以非???#xff0c;APP進入閃屏后,通過異步任務去完成其他DEX的加載,就能消除卡頓的過程。
第一種拆分DEX是官方支持的,開發者只需要打開multi-dex功能即可;第二種拆分DEX則需要開發者自己設計。
基于ClassLoader的動態加載都有個共同的特點,就是新的類一旦加載進內存了,就無法再次替換了,所以無法在運行時候升級功能,需要重啟APP才能生效。
運行在Native
有另一種動態加載方式是工作在Native層的,相比于ClassLoader,在Native層的動態加載不需要重新啟動APP就能生效,這類的加載有 加載SO庫 和 基于JNI HOOK 的熱修復。
加載SO庫
加載SO庫是最常見的Native動態加載,我們項目經常中使用SO庫,編譯APP的時候,SO并不會參與編譯,會原封不動被拷貝到APK包里的lib目錄下,安裝APK的時候,系統會掃描lib文件夾下支持當前設備CPU類型(比如arm或x86)的SO庫(APK包會帶有多種CPU類型對應的SO庫,安裝的時候只需要對應類型的)并拷貝到系統安裝目錄,APP在運行時可以調用 System#loadLibrary 方法動態加載對應的SO庫,此外還可以調用 System#load 加載指定路徑上的SO庫。
現在的APK里面往往帶有非常多的SO庫,而APP運行時只需要用到對應CPU類型的SO庫,因此把SO庫從APK包里剝離出來也是APK瘦身的有效手段。
JNI HOOK
基于JNI HOOK的熱修復技術的代表框架有阿里巴巴的 AndFix。Android中,修復BUG的方式就是更新類的方法,和ClassLoader通過加載新的類來更換方法的實現的想法一樣,AndFix 也是通過更換方法的做法來實現熱修復,不過做法比較取巧。Android中執行Native方法的時候,會去SO庫中查找對應的C/C++方法,而 AndFix 先把普通Java方法用Native方法代替,再通過更換不同SO庫還更換Native方法的實現。
總結
以上是生活随笔為你收集整理的Android插件化开发之动态加载的类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符串之数组中两个字符串的最小距离
- 下一篇: 字符串之括号的有效性