愛奇藝近日開源了其輕量級插件化方案 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
兼容性和穩定性
侵入性低
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還是走全量下載新插件,優化網絡下載流量。