您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)小程序如何實現(xiàn)多進程,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
小程序這個名詞相信大家已經(jīng)不陌生了,繼微信之后,阿里巴巴、百度、頭條等大廠相繼實現(xiàn)了自己的小程序。小程序是一種全新的開放能力,開發(fā)者能夠快速開發(fā)出小程序并集成進宿主,實現(xiàn)推廣等目的。
從使用角度看,小程序有輕量,易用等特點;
從技術(shù)角度,以Android端為例,小程序有部分組件原生化、UI和邏輯線程隔離、小程序之間進程隔離等等。
下面主要從小程序進程隔離角度出發(fā),分析BAT的小程序多進程的實現(xiàn)方案,并自己實現(xiàn)一個小程序的多進程。
多進程,顧名思義,即每一個小程序都是一個單獨的進程。這個效果只在Android端獨有。那為什么我們希望小程序之間實現(xiàn)進程隔離呢?原因大致有三點:
由于是單獨進程,無論小程序內(nèi)部因為何種原因的崩潰,對主進程都沒有影響,增強用戶體驗。
由于每個進程都有一片單獨的內(nèi)存區(qū)域,小程序不會占用主進程的內(nèi)存,降低了內(nèi)存溢出的風險。
由于不同進程間的內(nèi)存是隔離的,當同時開啟多個小程序時,內(nèi)存變量、參數(shù)等數(shù)據(jù)互不影響,也可達到一個解耦的目的。
既然是分析多進程這種用戶感知不強烈的技術(shù)點,我們需要通過一些工具或命令。
進程分析
首先,我們把微信完全殺死又重新開啟,然后通過 adb shell ps | grep com.tencent.mm 命令,可以查看正在運行的進程名稱和數(shù)量,其中 grep com.tencent.mm 是過濾微信相關(guān)的進程,因為微信的包名是com.tencent.mm。此時進程運行狀況如下圖:
此時我們只能看出微信從完全關(guān)閉到啟動,開啟了6個進程,但是還看不出這些是否與小程序相關(guān)。于是,我們打開一個小程序,再次執(zhí)行 adb shell ps | grep com.tencent.mm 命令,此時進程運行狀況如下圖:
對比之后,就可以做一些分析了。其中,com.tencent.mm是主進程,com.tencent.mm:push應(yīng)該是與推送相關(guān)的進程,com.tencent.mm.tools和com.tencent.mm:toolsmp應(yīng)該都是一個類似于Helper的相關(guān)進程,因此我認為最有可能的是com.tencent.mm:appbrand2,因為這個命名比較特殊,前面分別有appbrand0和appbrand1兩個進程出現(xiàn)過。那么為什么新開的第一個小程序,反而多出來的進程時appbrand2呢?我個人猜測這與微信小程序的預(yù)加載有關(guān)系,很有可能是,這個進程是空的,只是先fork出來,并沒有做過多的事情,真正承載我們開啟的那個小程序的進程,很有可能不是這個appbrand2。那么如何驗證呢?進入第二步,Activity分析。
首先打開一個小程序,然后通過 adb shell dumpsys activity activities 命令,可以看到所有棧內(nèi)的Activity信息,滑到頂部,查看正在與用戶交互的Activity信息,如下圖:
關(guān)鍵的信息我已經(jīng)用紅色圈了出來,processName=com.tencent.mm:appbrand0,realActivity=com.tencent.mm/.plugin.appbrand.ui.AppBrandUI,這大致已經(jīng)驗證了我們剛才的猜想,即:
com.tencent.mm:appbrand系列,是與小程序相關(guān)的進程。
微信預(yù)加載2個空進程作為預(yù)加載,避免用時再fork進程,耗時過長影響用戶體驗。
為了進一步驗證猜想是否正確,我下載了微信最新版本的apk,進行了逆向操作,也就是第三步,分析apk。
反編譯的方法大家自行搜索,這里就不贅述了。我們打開反編譯后的AndroidManifest.xml文件,搜索剛才的的Activity名稱,結(jié)果如下:
得到的信息與剛才一致。然而,我們又發(fā)現(xiàn)了另一個問題,那就是AppBrandUI還有另外4個兄弟,即AppBrandUI1,AppBrandUI2,AppBrandUI3,AppBrandUI4,而這四個Activity的名稱與綁定的進程,又能夠與一開始的appbrand對應(yīng)起來,經(jīng)過試驗,我發(fā)現(xiàn)微信最多只可以啟動5個小程序,而這些小程序的載體就是這5個Activity,不斷輪詢,超過5個時,將第一個結(jié)束掉。這樣,我們就基本可以確定,微信是通過apk內(nèi)置的5個Activity,來實現(xiàn)小程序的多開與進程隔離的。
因此,理論上這5個Activity應(yīng)該是除了進程不同,內(nèi)部邏輯應(yīng)該都是相同的,于是我們繼續(xù)驗證,反編譯代碼后找到AppBrandUI1這個Activity,結(jié)果如下圖:
AppBrandUI2,AppBrandUI3,AppBrandUI4與此完全一樣,都是繼承了AppBrandUI,做了極少的事,由于微信代碼混淆過,我們無法看出那幾行代碼具體做了什么,但是基本可以理解為完全復(fù)用。至于為什么分開寫,而不是復(fù)用同一個,我猜測原因可能有二:
由于語法限制,為Activity開辟進程需要在AndroidManifest.xml中預(yù)先配置
2. 微信不僅將小程序進程隔離,并且還進行了棧隔離,當我們同時開啟多個小程序時,長按Home鍵,可以發(fā)現(xiàn)存在多個小程序任務(wù)卡片,這種效果同樣需要在AndroidManifext.xml中配置taskAffinity屬性,這在上圖中也有體現(xiàn)。
另外,我還注意到,微信在AndroidManifest.xml中配置了這樣的Receiver:
這種Receiver共有5個,每個小程序進程有一個,其它4個只是繼承了這個AppBrandTaskPreloadReceiver,由于混淆的原因,無法看出具體做了什么事,但是通過名字判斷,是實現(xiàn)小程序進程預(yù)加載的,空閑時開啟這個廣播,至少可以提前開啟進程,避免用時再加載耗時過長影響用戶體驗。
同樣的,我分析了百度和支付寶的apk,通過命令和反編譯等方法,發(fā)現(xiàn)他們的方案幾乎一樣,只是預(yù)加載的數(shù)量等一些小細節(jié)不同,感興趣的同學可以自己逆向之后做對比。
分析總結(jié)
1. 微信對每個小程序都做了進程隔離和棧隔離,互不影響。
2. 實現(xiàn)這一功能的載體Activity是預(yù)先配置在AndroidManifest.xml中的。
3. 通過某種方法,微信將小程序的最大運行數(shù)量控制在5個。
4. 微信對多進程做了一些優(yōu)化,已知的是預(yù)加載2個空進程。
5. BAT等大廠的小程序多進程方案大同小異。
一. Application初始化
Android的app在開啟多進程時,每開啟一個進程,Application都會重新創(chuàng)建,也就是onCreate函數(shù)會被調(diào)用,如果沒有做進程判斷,所有東西會初始化多次,造成卡頓或意料之外的bug。
二. 分配與管控
由于進程之間的內(nèi)存無法共享,小程序的生命周期需要在某一個進程中維護,不然無法做到動態(tài)分配進程和棧,而這個進程選擇主進程最為合適。因此需要創(chuàng)建一個管理器,這個管理器負責以下幾件事:
1. 接收外界開啟、關(guān)閉等對小程序的操作
2. 合理的為接收到的請求分配空閑的進程
3. 接收遠程小程序的生命周期回調(diào)并通過某個uuid進行維護
4. 在空閑時預(yù)加載進程
5. 根據(jù)設(shè)置的可開啟的最大小程序數(shù)量,對進程進行新建、銷毀等操作
6. 所有這些管理和維護的操作,對小程序接入者都應(yīng)是透明的,無需關(guān)心具體實現(xiàn)流程,僅在需要時開啟小程序即可。
三. 進程生命周期問題
Android系統(tǒng)對于內(nèi)存有一套自己的管控機制,當內(nèi)存較為緊張時會在不做任何通知的情況下kill掉活躍度較低的進程,至于進程活躍程度,就與Android的進程保活有關(guān)了,可通過設(shè)置前臺進程、喚醒等方式去盡量?;?。但是無論應(yīng)用端再怎么做,都無法逾越操作系統(tǒng)的權(quán)限,系統(tǒng)在某些情況下依然會把進程殺死來保證整個系統(tǒng)的正常運行。因此,開發(fā)時需要做容錯處理,不能僅以Activity的onDestroy回調(diào)為準,因為一旦出現(xiàn)系統(tǒng)級的回收,很可能導(dǎo)致整個分配管理器的錯亂。
四. 通訊
通信又分為兩個方面,第一,小程序進程與app主進程是隔離的,需要進程間的IPC通信;第二,小程序的本質(zhì)是一個web容器,這就少不了js與原生的通信,需要jsbridge。下面分別說一下這兩個方面。進程通信:
IPC的實現(xiàn)已經(jīng)不是什么問題,這里僅說幾個需要注意的點:
1. 通信一定是雙向的,無論哪個進程,最好綁定同一個服務(wù),方便數(shù)據(jù)的維護。
2. 由于通信較為頻繁,建議使用基于Binder的通信機制,可以提高運行效率。
js與原生通信:
js與原生通信一定是通過jsbridge,最好做法是將原生方法的實現(xiàn)寫在主進程,分布在不同進程的小程序向主進程請求某個bridge的實現(xiàn)結(jié)果,主進程根據(jù)相應(yīng)的參數(shù)去執(zhí)行并返回結(jié)果,類似于一套CS的架構(gòu)。即小程序客戶端無需關(guān)心具體操作,只關(guān)心結(jié)果并響應(yīng)給web端。
關(guān)于小程序如何實現(xiàn)多進程就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。