小程式如何實現多程式?從隔離角度出發,看完你就會懂!

yilian發表於2020-01-10
小程式如何實現多程式?從隔離角度出發,看完你就會懂!

前言

小程式這個名詞相信大家已經不陌生了,繼微信之後,阿里巴巴、百度、頭條等大廠相繼實現了自己的小程式。小程式是一種全新的開放能力,開發者能夠快速開發出小程式並整合進宿主,實現推廣等目的。
從使用角度看,小程式有輕量,易用等特點;
從技術角度,以Android端為例,小程式有部分元件原生化、UI和邏輯執行緒隔離、小程式之間程式隔離等等。

本篇文章主要從小程式程式隔離角度出發,分析BAT的小程式多程式的實現方案,並自己實現一個小程式的多程式。

如果有朋友需要從頭開學,那就可以分享我整理好的內容  小程式開發教程

多程式的意義

多程式,顧名思義,即每一個小程式都是一個單獨的程式。這個效果只在Android端獨有。那為什麼我們希望小程式之間實現程式隔離呢?原因大致有三點:

  1. 由於是單獨程式,無論小程式內部因為何種原因的崩潰,對主程式都沒有影響,增強使用者體驗。

  2. 由於每個程式都有一片單獨的記憶體區域,小程式不會佔用主程式的記憶體,降低了記憶體溢位的風險。

  3. 由於不同程式間的記憶體是隔離的,當同時開啟多個小程式時,記憶體變數、引數等資料互不影響,也可達到一個解耦的目的。

對微信小程式的分析

既然是分析多程式這種使用者感知不強烈的技術點,我們需要透過一些工具或命令。

程式分析

首先,我們把微信完全殺死又重新開啟,然後透過 adb shell ps | grep com.tencent.mm 命令,可以檢視正在執行的程式名稱和數量,其中 grep com.tencent.mm 是過濾微信相關的程式,因為微信的包名是com.tencent.mm。此時程式執行狀況如下圖:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!

此時我們只能看出微信從完全關閉到啟動,開啟了6個程式,但是還看不出這些是否與小程式相關。於是,我們開啟一個小程式,再次執行 adb shell ps | grep com.tencent.mm 命令,此時程式執行狀況如下圖:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!

對比之後,就可以做一些分析了。其中,com.tencent.mm是主程式,com.tencent.mm:push應該是與推送相關的程式,com.tencent.mm.tools和com.tencent.mm:toolsmp應該都是一個類似於Helper的相關程式,因此我認為最有可能的是com.tencent.mm:appbrand2,因為這個命名比較特殊,前面分別有appbrand0和appbrand1兩個程式出現過。那麼為什麼新開的第一個小程式,反而多出來的程式時appbrand2呢?我個人猜測這與微信小程式的預載入有關係,很有可能是,這個程式是空的,只是先fork出來,並沒有做過多的事情,真正承載我們開啟的那個小程式的程式,很有可能不是這個appbrand2。那麼如何驗證呢?進入第二步,Activity分析。

Activity分析

首先開啟一個小程式,然後透過 adb shell dumpsys activity activities 命令,可以看到所有棧內的Activity資訊,滑到頂部,檢視正在與使用者互動的Activity資訊,如下圖:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!

關鍵的資訊我已經用紅色圈了出來,processName=com.tencent.mm:appbrand0,realActivity=com.tencent.mm/.plugin.appbrand.ui.AppBrandUI,這大致已經驗證了我們剛才的猜想,即:

  • com.tencent.mm:appbrand系列,是與小程式相關的程式。

  • 微信預載入2個空程式作為預載入,避免用時再fork程式,耗時過長影響使用者體驗。

為了進一步驗證猜想是否正確,我下載了微信最新版本的apk,進行了逆向操作,也就是第三步,分析apk。

微信Apk分析

反編譯的方法大家自行搜尋,這裡就不贅述了。我們開啟反編譯後的AndroidManifest.xml檔案,搜尋剛才的的Activity名稱,結果如下:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!

得到的資訊與剛才一致。然而,我們又發現了另一個問題,那就是AppBrandUI還有另外4個兄弟,即AppBrandUI1,AppBrandUI2,AppBrandUI3,AppBrandUI4,而這四個Activity的名稱與繫結的程式,又能夠與一開始的appbrand對應起來,經過試驗,我發現微信最多隻可以啟動5個小程式,而這些小程式的載體就是這5個Activity,不斷輪詢,超過5個時,將第一個結束掉。這樣,我們就基本可以確定,微信是透過apk內建的5個Activity,來實現小程式的多開與程式隔離的。

因此,理論上這5個Activity應該是除了程式不同,內部邏輯應該都是相同的,於是我們繼續驗證,反編譯程式碼後找到AppBrandUI1這個Activity,結果如下圖:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!

AppBrandUI2,AppBrandUI3,AppBrandUI4與此完全一樣,都是繼承了AppBrandUI,做了極少的事,由於微信程式碼混淆過,我們無法看出那幾行程式碼具體做了什麼,但是基本可以理解為完全複用。至於為什麼分開寫,而不是複用同一個,我猜測原因可能有二:

  1. 由於語法限制,為Activity開闢程式需要在AndroidManifest.xml中預先配置

2. 微信不僅將小程式程式隔離,並且還進行了棧隔離,當我們同時開啟多個小程式時,長按Home鍵,可以發現存在多個小程式任務卡片,這種效果同樣需要在AndroidManifext.xml中配置taskAffinity屬性,這在上圖中也有體現。

另外,我還注意到,微信在AndroidManifest.xml中配置了這樣的Receiver:

小程式如何實現多程式?從隔離角度出發,看完你就會懂!
小程式如何實現多程式?從隔離角度出發,看完你就會懂!

這種Receiver共有5個,每個小程式程式有一個,其它4個只是繼承了這個AppBrandTaskPreloadReceiver,由於混淆的原因,無法看出具體做了什麼事,但是透過名字判斷,是實現小程式程式預載入的,空閒時開啟這個廣播,至少可以提前開啟程式,避免用時再載入耗時過長影響使用者體驗。

同樣的,我分析了百度和支付寶的apk,透過命令和反編譯等方法,發現他們的方案几乎一樣,只是預載入的數量等一些小細節不同,感興趣的同學可以自己逆向之後做對比。

分析總結

1. 微信對每個小程式都做了程式隔離和棧隔離,互不影響。

2. 實現這一功能的載體Activity是預先配置在AndroidManifest.xml中的。

3. 透過某種方法,微信將小程式的最大執行數量控制在5個。

4. 微信對多程式做了一些最佳化,已知的是預載入2個空程式。

5. BAT等大廠的小程式多程式方案大同小異。

實現小程式多程式的關鍵點

一. Application初始化

Android的app在開啟多程式時,每開啟一個程式,Application都會重新建立,也就是onCreate函式會被呼叫,如果沒有做程式判斷,所有東西會初始化多次,造成卡頓或意料之外的bug。

二. 分配與管控

由於程式之間的記憶體無法共享,小程式的生命週期需要在某一個程式中維護,不然無法做到動態分配程式和棧,而這個程式選擇主程式最為合適。因此需要建立一個管理器,這個管理器負責以下幾件事:

1. 接收外界開啟、關閉等對小程式的操作

2. 合理的為接收到的請求分配空閒的程式

3. 接收遠端小程式的生命週期回撥並透過某個uuid進行維護

4. 在空閒時預載入程式

5. 根據設定的可開啟的最大小程式數量,對程式進行新建、銷燬等操作

6. 所有這些管理和維護的操作,對小程式接入者都應是透明的,無需關心具體實現流程,僅在需要時開啟小程式即可。

三. 程式生命週期問題

Android系統對於記憶體有一套自己的管控機制,當記憶體較為緊張時會在不做任何通知的情況下kill掉活躍度較低的程式,至於程式活躍程度,就與Android的程式保活有關了,可透過設定前臺程式、喚醒等方式去儘量保活。但是無論應用端再怎麼做,都無法逾越作業系統的許可權,系統在某些情況下依然會把程式殺死來保證整個系統的正常執行。因此,開發時需要做容錯處理,不能僅以Activity的onDestroy回撥為準,因為一旦出現系統級的回收,很可能導致整個分配管理器的錯亂。

四. 通訊

通訊又分為兩個方面,第一,小程式程式與app主程式是隔離的,需要程式間的IPC通訊;第二,小程式的本質是一個web容器,這就少不了js與原生的通訊,需要jsbridge。下面分別說一下這兩個方面。 程式通訊:

IPC的實現已經不是什麼問題,這裡僅說幾個需要注意的點:

1. 通訊一定是雙向的,無論哪個程式,最好繫結同一個服務,方便資料的維護。

2. 由於通訊較為頻繁,建議使用基於Binder的通訊機制,可以提高執行效率。

js與原生通訊:

js與原生通訊一定是透過jsbridge,最好做法是將原生方法的實現寫在主程式,分佈在不同程式的小程式向主程式請求某個bridge的實現結果,主程式根據相應的引數去執行並返回結果,類似於一套CS的架構。即小程式客戶端無需關心具體操作,只關心結果並響應給web端。

結語

認真分析之後發現微信小程式做的最佳化還是很多的,從xml中還可以看出一些代理類等等。我個人得出的結論大概就是這些,歡迎指正和補充,謝謝!

BATJ、位元組跳動面試專題,演算法專題,高階技術專題,混合開發專題,java面試專題,Android,Java小知識,到效能最佳化.執行緒.View.OpenCV.NDK等已經上傳到了的我的GitHub
大家點選我的GitHub地址: 點下star一起學習


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952849/viewspace-2672927/,如需轉載,請註明出處,否則將追究法律責任。

相關文章