小程式如何實現多程式?從隔離角度出發,看完你就會懂!
前言
小程式這個名詞相信大家已經不陌生了,繼微信之後,阿里巴巴、百度、頭條等大廠相繼實現了自己的小程式。小程式是一種全新的開放能力,開發者能夠快速開發出小程式並整合進宿主,實現推廣等目的。
從使用角度看,小程式有輕量,易用等特點;
從技術角度,以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分析。
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,做了極少的事,由於微信程式碼混淆過,我們無法看出那幾行程式碼具體做了什麼,但是基本可以理解為完全複用。至於為什麼分開寫,而不是複用同一個,我猜測原因可能有二:
- 由於語法限制,為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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 你與小程式開發的距離有多遠?
- MySQL是如何實現事物隔離?MySql
- 你知道如何用 PHP 實現多程式嗎?PHP
- 如何確定Kaizen的實施機會?看完秒懂AI
- 看完這場分享會,你將更懂如何在快手上“買量”
- 初學者如何從零學習人工智慧?看完你就懂了人工智慧
- Java如何實現消費資料隔離?Java
- WPF 通過程式實現異常隔離的客戶端客戶端
- 你是否真的懂 [程式的執行順序] 多程式 / 程式池
- 10行程式碼實現微信小程式支付功能,使用小程式雲開發實現小程式支付功能(行程微信小程式
- 一看就懂的python小程式-支援多執行緒聊天例項Python執行緒
- 看完秒懂!Python就業前景及發展趨勢!Python就業
- 從程式碼層讀懂 Java HashMap 的實現原理JavaHashMap
- Eureka 多環境隔離方案(包含本地開發人員間隔離)
- 前端沙箱利用這些特性實現程式碼的隔離和限制前端
- 看完就懂,五千字長文帶你領略推薦系統
- 從微信小程式開發者工具原始碼看實現原理(二)- - 小程式技術實現微信小程式原始碼
- Java反射,看完就會用Java反射
- 小程式開發進階:如何實現直播連麥
- 如何製作一個鮮花微信小程式?看完這篇新手教程就知道了!微信小程式
- 看完這篇 Linux 的基本操作你就會了!Linux
- 三分鐘圖解事務隔離級別,看一遍就懂圖解
- 微信小程式實現釋出作業微信小程式
- 三句程式碼建立全屏Dialog或者DialogFragment:帶你從原始碼角度實現Fragment原始碼
- 利用 Webpack 實現小程式多專案管理Web專案管理
- 乾貨:如何藉助小程式雲開發實現小程式支付功能(含原始碼)原始碼
- 如何利用tox打造自動自動化測試框架,看完就懂框架
- [轉] 如何實現 React 寫小程式-1React
- 學習小程式從“你”開始
- 《包你懂系列》一文講清楚 MySQL 事務隔離級別和實現原理,開發人員必備知識點MySql
- 【小程式】微信小程式開發實踐微信小程式
- 小程式開發:python sanic 實現小程式登入註冊Python
- Win10系統間隔幾秒就會發出咚咚咚提示音如何關閉Win10
- 從程式設計師小仙飛昇上神,java技術開發要如何實現?程式設計師Java
- 小程式如何發紅包
- 基於MySql主從分離的程式碼層實現MySql
- Laravel 與 jwt 多表(多使用者端)驗證隔離的實現LaravelJWT
- 【自動化】使用PlayWright+代理IP實現多環境隔離