您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關小程序如何實現多進程,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
小程序這個名詞相信大家已經不陌生了,繼微信之后,阿里巴巴、百度、頭條等大廠相繼實現了自己的小程序。小程序是一種全新的開放能力,開發者能夠快速開發出小程序并集成進宿主,實現推廣等目的。
從使用角度看,小程序有輕量,易用等特點;
從技術角度,以Android端為例,小程序有部分組件原生化、UI和邏輯線程隔離、小程序之間進程隔離等等。
下面主要從小程序進程隔離角度出發,分析BAT的小程序多進程的實現方案,并自己實現一個小程序的多進程。
多進程,顧名思義,即每一個小程序都是一個單獨的進程。這個效果只在Android端獨有。那為什么我們希望小程序之間實現進程隔離呢?原因大致有三點:
由于是單獨進程,無論小程序內部因為何種原因的崩潰,對主進程都沒有影響,增強用戶體驗。
由于每個進程都有一片單獨的內存區域,小程序不會占用主進程的內存,降低了內存溢出的風險。
由于不同進程間的內存是隔離的,當同時開啟多個小程序時,內存變量、參數等數據互不影響,也可達到一個解耦的目的。
既然是分析多進程這種用戶感知不強烈的技術點,我們需要通過一些工具或命令。
進程分析
首先,我們把微信完全殺死又重新開啟,然后通過 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分析。
首先打開一個小程序,然后通過 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。
反編譯的方法大家自行搜索,這里就不贅述了。我們打開反編譯后的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,做了極少的事,由于微信代碼混淆過,我們無法看出那幾行代碼具體做了什么,但是基本可以理解為完全復用。至于為什么分開寫,而不是復用同一個,我猜測原因可能有二:
由于語法限制,為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端。
關于小程序如何實現多進程就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。