愛奇藝開源輕量級外掛化方案 Neptune
愛奇藝近日開源了其輕量級外掛化方案 Neptune,專案地址:https://github.com/iqiyi/Neptune
外掛化框架可以在主程式不重新安裝的情況下,針對單個業務模組進行動態載入達到模組更新的目的,整個載入更新過程,對使用者來說也是無感知的。
在愛奇藝APP快速發展的歷程中,需要外掛化的原因,歸結起來有以下幾點:
-
業務快速發展,程式碼膨脹,APP不可避免地遇到了65536的大坑
-
程式碼量增大帶來了APK包體積的增加,而愛奇藝APK包體積一直在競品中保持領先地位
-
模組耦合度高,協作開發困難,編譯時間長
-
應用頻繁更新,使用者粘性降低,新版本覆蓋率和覆蓋速度不滿足業務需求
-
新功能開發,需要支援動態升級,外掛動態下發形式可以完成模組的熱部署和實時更新
愛奇藝APP從2013年就開始了外掛化技術的研究和改造,截止目前一共有20多個獨立業務模組以外掛化的方式執行和並行迭代,其中包括APP首頁的奇秀、文學、電影票、漫畫等業務。開發外掛化框架的Demo並不是很難,但是要開發一款完善的外掛化框架,相容適配國產各種碎片化的ROM,同時滿足業務需求,卻不是那麼容易。外掛框架的穩定性和相容性,從原有程式碼模組解耦到外掛化的遷移成本、後期維護成本等方面都需要考慮到。本文將介紹外掛化實現的技術原理,分享愛奇藝APP在外掛化實踐過程的解決方案。
Neptune是愛奇藝移動端研發的一套靈活,穩定,輕量級的外掛化解決方案。經過不斷的研發,迭代和線上驗證,目前已經完全適配了Android P,能夠在數億的裝置上動態載入和執行外掛APK,為愛奇藝眾多的垂直業務團隊提供了穩定的服務。
Neptune的特性
功能完善,支援Activity/Service/Recevier,幾乎支援所有Android原生特性。由於ContentProvider使用場景較少,暫時沒有支援。
-
四大元件無需在宿主Manifest中預先註冊,元件具備完整的生命週期
-
Activity:支援顯式和隱式呼叫,支援theme,luanchMode,taskAffinity,支援透明主題
-
Service:支援顯式和隱式呼叫,支援start,stop,bind,unbind等操作
-
BroadcastReceiver:支援靜態廣播和動態廣播
-
支援共享宿主的程式碼和資源,實現資源分割槽
-
支援外掛之間存在相互依賴,程式碼共享
-
外掛ClassLoader和資源互相隔離,避免類衝突和資源重名
-
宿主Activity容器支援載入外掛中的Fragment和View
相容性和穩定性
-
幾乎相容市面上所有的Android裝置
-
極少的Hook,核心Hook點只有Instrumentation和AssetManager,沒有binder hook
-
外掛可以執行在獨立程序,與宿主完全隔離,互不干擾
-
外掛之間類是隔離的,不會出現重複類的問題
-
外掛使用自身的AssetManager,沒有Hook宿主的Resources,無需適配小米,vivo等ROM
侵入性低
-
外掛開發和開發原生APP類似
-
外掛可以依賴宿主的程式碼和資源,也可以完全不依賴
-
外掛和宿主可以獨立打包和編譯,並行迭代
-
外掛依賴宿主的資源,通過Gradle外掛自動完成資源適
配和處理,對開發者透明
Neptune的架構圖
Neptune整個框架實現是非常輕量級的,沒有包含外掛下載/安裝/版本管理的邏輯,提供了PluginClassLoader,PluginContextWrapper,ActivityProxy,ResourcesProxy等基礎元件實現了全面外掛化。更多細節歡迎訪問Github,Read the fucking source code。
外掛管理中心
在Neptune框架之上,愛奇藝APP針對外掛業務,實現了一套完備的外掛管理方案,負責外掛的下載,安裝,升級,版本管理,外掛啟動控制,外掛與宿主之間的通訊。由於這部分涉及具體APP業務的互動形態,且與後端資料結構關聯,因此沒有開源。
這裡簡單介紹下設計思路。對於每一個外掛版本資料,在APP層是一個OnLineInstance例項,裡面欄位與後端資料結構保持一致,包含基本的外掛包名,外掛版本,外掛依賴,還包含一些下載控制策略,patch升級策略等。APP層的OnLineInstance,對應於Neptune框架的PluginLiteInfo。由於一些外掛可能會來自不同的地方或者配置不同的版本,如內建外掛,本地快取的舊版本外掛,線上最新外掛。因此在APP層一個外掛業務會關聯多個OnLineInstance,我們會選擇最高版本的相容外掛進行升級,安裝。
外掛例項狀態機
一個外掛OnLineInstance從初始狀態(OriginalState)到可用狀態(InstalledState)有一套嚴格的狀態機演變。版本不相容的外掛例項會被下線,優先使用本地已安裝版本,空閒時機下載升級最新的外掛,儘量做到讓使用者使用無感知。
外掛增量更新
外掛包體積越大,下載成功率和轉化率越低,為了提高外掛升級的覆蓋率和成功率,我們採用了增量更新的機制。外掛後臺更新外掛時,後臺會基於歷史版本外掛生成增量的diff包。APP端在請求外掛資料時,後端介面額外返回增量patch的url及生成patch所有的base外掛版本。前端根據本地已安裝外掛的版本,選擇使用patch增量合成新版本外掛apk還是走全量下載新外掛,優化網路下載流量。