大型移動應用解決之道 - 插件化

插件化這個詞相信讀者並不陌生,比如,我們的IDE(eclipse,As)都具有支持插件的能力,如果瞭解Windows開發的讀者對DLL這種機制也並不陌生,包括一些Web應用服務器(jboss),他們也都實現了osgi的模塊化的規範,可以實現類似插件的功能,在無需停止服務器的前提下就可以上線一些需求或動態的替換組件和模塊的實現等。 但是在Android系統中是不支持這種開發模式,需要我們的開發人員自己去實現這麼一套支持插件化的框架系統。

我們先看下插件化的研發流程是怎樣的?例如下圖的ModuelA與B的簡單並行研發流程:



面臨的問題?

如果讀者閱讀了多進程化”的那篇文章,應該瞭解在功能需求單向遞增這種情況下,不僅要面臨內存帶來的穩定性問題,同時也面臨系統本身和團隊協作帶來的種種問題:


1. 方法數的限制

由於dex文件格式的限制,一個dex文件中方法個數存儲是short類型不能超過65536,如果超過這個數將不能打包。 另外,方法數過大,會導致dexopt崩潰,dexopt是使用LinearAlloc來存儲應用的方法信息,如果一旦超出這個緩衝區的大小,即使能夠打包成功,那麼可能在一些機器上也是無法進行安裝的。

2. 安裝包體積

功能需求單向遞增之後,最直觀看到的就是安裝包體積變大。安裝包體積變大,其實不是一件小事情。最直接影響的就是升級轉化,由於安裝包比之前大很多,在用戶下載的過程中失敗的概率也會增加,這樣老版本升級成新版本的成功率也會下降。而且,很多用戶也會比較在意安裝包的大小。他可能會認爲安裝包小的在運行時會更流暢等等。

3. 團隊耦合嚴重

功能需求單向遞增之後,團隊之間的耦合度越來越高,依賴更強。我們知道要發佈一個產品是以APK的形式發出的,APK是我們大家統一把代碼打包成DEX文件,然後把DEX文件通過APKbuilder打包成APK的。 那麼既然要統一打包,大家需要將修改的問題都全部修改完成並且提交到SCM上纔可以進行打包。  但是這種方式,在模塊量很大的情況下,會出現互相等待的情況。 比如:A,B,C三個模塊的研發負責人,A,B已經修改完成並自測通過提交了代碼,C還在修改中,那麼就不能進行打包, 而且C的進度可能還會影響A,B的下一步計劃。 這是非常糟糕的,而且非常影響產品的迭代速度。 這三個人就像是綁在一起的螞蚱,誰也蹦不遠,跑不快。

4. 編譯打包慢

功能需求增加,意味着代碼量與資源數的增加,那麼就會拉低整個APK的打包速度,如果在遇到垃圾的服務器配置,那麼幾分鐘,10幾分鐘的打包時間並不稀奇。 這是非常痛苦的,通常產品在發佈前,研發會進行功能冒煙自測和穩定性的自動化測試,如果在測試過程中發現異常,需要在來一輪打包和自測。 我的天呢, 崩潰了。

5. 靈活性差

在一些電商應用中,某個活動日,要支持一些業務上線,如果要求用戶升級應用才能支持,那麼這是很影響業務的(等用戶全部替換成新的版本,活動時間早以過期),在或者某個組件模塊發生了嚴重問題,如何解決? 升級解決?


如果以上問題繼續持續下去,產品很難繼續保持和其他競品的優勢或追趕其他產品,所以必須對現有產品軟件架構進行調整,對現有研發流程進行調整。

 

分析


從上圖我們可以看出,一個應用程序包含所有的模塊,並且各個模塊間依賴嚴重;

還記得我們解決內存問題時的思路嗎?“分離”,“分割”,“分解” 他們就像是“應急錦囊”一樣,能幫助我們分析問題。 回想我們在解決內存問題時,核心的問題是“N個模塊爭搶同一個進程內存”導致了很多穩定性問題,而我們就將不同的模塊分解到不同的進程中,達到不同模塊擁有自己的內存空間,這樣就不存在爭搶,穩定性問題也會得到改善。 而從上面4個問題總結下來就是“N個模塊爭搶同一個DEX”的問題,N個模塊同時被打包到同一個DEX,那麼DEX大了之後, 影響打包速度,影響升級轉化,影響版本迭代等等。 所有的問題,均指向了將所有的代碼打包到同一個DEX中導致的。 那麼按照解決內存問題的思路,去分解。將N個模塊分解到不同的DEX中,是不是就可以解決?

 

什麼是插件化?

插件化簡單講就是將各個模塊拆分成不同的包(DEX,JAR,APK等),而這些包“無需安裝”就可以被主應用加載,提供給用戶使用。




爲什麼要實現插件化?

按照上面的分析,我們要把各個模塊分解到不同的APK中,每個APK對應一個或多個獨立的模塊,主APK中只包含核心的功能模塊,其餘功能模塊,均根據用戶在使用時按需下載。

這樣主APK不會出現方法數限制,安裝包體積自然下降,主APK與子APK獨立開發,獨立升級維護,如果有依賴也僅是接口的依賴,這樣耦合會降低,各個APK間沒有代碼的依賴,編譯打包也會有很大改善,同時插件化帶來的靈活性和動態性是每一個產品經理所渴望的如獲至寶

 

既然插件化是如此美的一個東西,那麼我們怎樣才能擁有她。 美的東西,通常很難得到,需要幾番周折,花大把時間和精力。即使得到之後,你的研發流程可能會有所調整。 就像我們得到了一個至寶,我們可能需要給她買個保險箱,可能還需要有專門的人負責看護一樣,那麼和你之前的生活流程完全不同。 沒有辦法,擁有美的東西,是要付出代價的。

 

如何拆分出插件?

我認爲基本和多進程的拆分原則相同,即按照職責驅動設計模式進行拆分,同時參考OSGI模塊化規範。

插件拆分的原則,請參考:

1. 插件間僅接口依賴(雙方協議)

2. 隔離性(插件間實現的變化互不影響)

3. 可替代性(可任意時刻對插件的實現進行替換,同時不影響其他插件的運行)

還是要注意一點,拆分出來的插件儘量要保證能夠獨立的運行,能夠作爲一個獨立的業務功能運行。即可以作爲插件被加載到主應用中,也可以作爲獨立的應用對外發布。這樣的話,我們產品的靈活性是很高的,就像擁有了一個插件化的倉庫,隨意組裝,拼接,就能發佈一個產品,豈不是妙哉。

 

插件化框架如何選擇?

在上面我們也提到了,android目前的系統是不支持插件化的,如果應用要使用插件化的軟件架構,則需要移動端開發人員完成插件化框架系統的實現。 要實現這麼一個系統,並不是件易事,團隊中還是要有牛逼的開發人員,並且對andoird系統有一定的瞭解。否則很難將這樣一個系統應用到產品中。 插件化的框架實現,目前也有很多開源的,比如:DroidPluginReplugin等等,實現的技術方法也有所不同。讀者如果要引入插件化,還是要參考下這些框架的實現,或者直接使用他們。

 

向大家推薦以下文章,請參考:

 

DroidPlugin:

Githubhttps://github.com/DroidPluginTeam/DroidPlugin

源碼分析:http://blog.csdn.net/turkeycock/article/details/50959786

 

Replugin

Githubhttps://github.com/Qihoo360/RePlugin

源碼分析:https://www.jianshu.com/p/5994c2db1557

 

筆者都有閱讀過上面兩個框架的代碼,本人還是比較看好Replugin的。DroidPlugin更多的是在於對系統的Hook,穩定性是很大的問題。而RepluginHook了系統一個點,就是LoadedApk中的PathClassloaderhook,所以穩定性大大提高。

 

下面這篇文章由筆者編寫,是對這兩款插件的不同實現之處的總結,請做爲參考:

DroidPluginReplugin實現比較:http://blog.csdn.net/degwei/article/details/79043165

 

另外,在向大家推薦一篇文章

http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up

這篇文檔介紹了插件的發家史和一些框架的技術實現輪廓。


寫到這裏,不知道讀者是不是已經對插件化有了一些瞭解。如果讀者在拆分和實現的過程中有任何問題,我們可以一起討論。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章