服務項目
品牌網站建設

數字營銷

係統平台開發

數字產品

安全運維

Menu
官网开云
官网开云
微信小程序架構分析《一》調試技巧,模塊構成,理念分析
時間:2020-07-15 10:36:53

本文分為(wei) 以下幾個(ge) 部分:

  • 小程序調試技巧
  • 小程序主要模塊構成
  • 小程序模塊間通信
  • 設計理念分析

小程序調試技巧

微信開發者工具默認禁用了右鍵打開調試麵板功能,我們(men) 可以修改開發者工具部分代碼移除該限製。

  • 找到 app.nw 項目根目錄,Mac 下為/Applications/wechatwebdevtools.app/Contents/Resources/app.nw
  • 使用 js-beautify 對代碼批量格式化:


    cd /Applications/wechatwebdevtools.app/Contents/Resources/app.nw find . -type f -name '*.js' -not -path "./node_modules/*" -not -path "./modified_modules/*" -exec js-beautify -r -s 2 -p -f '{}' \;

  • 注釋掉文件 app/dist/app.js 44 行和app/dist/components/simulator/webviewbody.js 149 行preventDefault 調用。101100 版本還需要修改 package.json 文件,去掉 --disable-devtools。

執行完以上操作就可以右鍵打開頁麵的調試麵板了,需要特別注意的是,使用 view 頁麵的麵板後會(hui) 導致 wxml 麵板不可用,touch 事件無法響應等種種問題,請慎重使用。

通過代碼可以發現,在配置目錄下添加 config.json 文件,然後加入{isDev:true} 可以啟用開發者工具所謂的調試模式, 但是我在配置後程序無法正常啟動,隻好暫時先放棄這種方式。

小程序主要模塊構成

小程序自身分為(wei) 兩(liang) 個(ge) 主要部分獨立運行:view 模塊和 service 模塊。在開發者工具中,它們(men) 獨立運行於(yu) 不同的 webivew tag 中。

view 模塊負責 UI 顯示,它由開發者編寫(xie) 的 wxml 和 wxss 轉換後代碼以及微信提供相關(guan) 輔助模塊組成。 一個(ge) view 模塊對應一個(ge) webview 組件(也就是我們(men) 常規理解的一個(ge) 頁麵), 小程序支持同時多個(ge) view 存在。view 模塊通過 WeixinJSBridge 對象來跟後台通信。

service 模塊負責應用的後台邏輯,它由小程序的 js 代碼以及微信提供的相關(guan) 輔助模塊組成。 一個(ge) 應用隻有一個(ge) service 進程,它同樣也是一個(ge) 頁麵(至少在開發者工具內(nei) 如此,上線後可能運行於(yu) WeixinJSCore 之內(nei) ),與(yu) view 模塊不同的是,它在程序生命周期內(nei) 後台運行,service 模塊通過與(yu) view 模塊實現不同但接口格式一樣的 WeixinJSBridge 對象跟後台通信。

小程序模塊間通信

(開發者工具內(nei) 各模塊通信圖)

做過微信開發相關(guan) 的開發者會(hui) 對 WeixinJSBridge 這個(ge) 對象有所了解,它就是負責 UI 與(yu) 後台 進行交互的一個(ge) 中間層。應用號的 WeixinJSBridge 相比與(yu) 之前的微信 webview 多出 publish 和 subscribe 兩(liang) 個(ge) 公共方法來發布和訂閱事件,從(cong) 而進行雙向通信。


service 模塊的 WeixinJSBridge 對象在文件app/dist/weapp/appservice/asdebug.js 中定義(yi) , view 層的 WeixinJSBridge 在文件 app/dist/inject/jweixindebug.js 中定義(yi) 。 盡管兩(liang) 者都使用一樣的接口以及使用 postMessage 方法與(yu) 後台通信,但是其內(nei) 部所做的事情確是完全不同的, 例如 service 模塊可以直接通過 prompt 方法來通過 prompt調起底層組件,而 view 層的 WeixinJSBridge 隻能發送消息 (參考 H5與(yu) Native交互之JSBridge技術)。

我們(men) 來看一個(ge) 典型的交互流程:

  1. 用戶點擊界麵觸發事件
  2. 對應 view 模塊接收事件後將事件封裝成所需格式後調用 publish 方法發送:


    WeixinJSBridge.publish('PAGE_EVENT', data)

    data 參數舉(ju) 例:


    { "data": { "eventName": "onhidetap", "data": { "target": { ... }, "currentTarget": { ... }, "type": "tap", "timeStamp": 11457, "touches": [ ... ], "detail": { ... } } }, "options": { "timestamp": 1475445858336 } }

  3. 後台(開發者工具內(nei) 為(wei) nwjs 運行環境)將數據處理後發送給 service 模塊,數據形如:


    { "to": "appservice", "msg": { "eventName": "PAGE_EVENT", "data": { "data": { "eventName": "onhidetap", "data": { "target": { ... }, "currentTarget": { ... }, "type": "tap", "timeStamp": 75329, "touches": [ ... ], "detail": { ... } } }, "options": { "timestamp": 1475445858336 } }, "webviewID": 0 }, "command": "MSG_FROM_WEBVIEW" }

  4. service 模塊的 WeixinJSBridge 內(nei) 回調函數依據傳(chuan) 來數據找到對應 view 的 page 模塊後執行 對應名為(wei) eventName 指向的函數

  5. 回調函數調用 this.setData({hidden: true}) 改變 data,serivce 層計算該頁麵 data 後向後台發送 send_app_data 和 appdataChange 事件,具體(ti) 數據格式如下:


    { "appData": { "page/index": { ... } }, "sdkName": "send_app_data", "to": "backgroundjs", "comefrom": "webframe", "command": "COMMAND_FROM_ASJS", "appid": "touristappid", "appname": "chat", "apphash": 70475629, "webviewID": 100000 }

    { "eventName": "appDataChange", "data": {   "data": {     "data": {       "hidden": true     }   },   "options": {     "timestamp": 1475528706311   } }, "sdkName": "publish", "webviewIds": [   0 ], "to": "backgroundjs", "comefrom": "webframe", "command": "COMMAND_FROM_ASJS", "appid": "touristappid", "appname": "chat", "apphash": 70475629, "webviewID": 100000 } 
  6. 後台(文件 dist/components/simulator/webviewbody.js) 接收到appDataChange 事件數據後再將數據進行簡單封裝, 最後轉發給到 view 層。 具體(ti) 數據格式為(wei) :


    { "to": "webframe", "msg": { "eventName": "appDataChange", "data": { "data": { "data": { "hidden": true } }, "options": { "timestamp": 1475528706311 } }, "sdkName": "publish", "webviewIds": [ 0 ], "to": "backgroundjs", "comefrom": "webframe", "command": "COMMAND_FROM_ASJS", "appid": "touristappid", "appname": "chat", "apphash": 70475629, "webviewID": 100000, "act": "sendMsgFromAppService" }, "command": "MSG_FROM_APPSERVICE", "webviewID": 0, "id": 0.10577065353216675 }

  7. view 層的 WeixinJSBridge 接收到後台的數據,如果 webviewID 匹配則將 data 與(yu) 現有頁麵 data 合並, 然後就是 virtual dom 模塊進行 diff 和 apply 操作改變 dom。

小程序模塊間消息傳(chuan) 遞除了界麵事件和應用數據還包括觸發原生方法、握手以及生命周期等類型, 盡管處理對象和處理方式不同,大體(ti) 流程跟上麵是一樣的。


view 模塊和 service 模塊的 WeixinJSBridge 都使用了 postMessage 接口 (參考MDN 文檔) 與(yu) 後台通信,但是由於(yu) 該接口無法直接與(yu) nwjs 後台進程通信,所以開發者工具會(hui) 將 app/dist/contentscript/contentScript.js 文件做為(wei) contentScript 注入到 view 模塊和 service 模塊所在頁麵,contentScript.js 的代碼提供了 message 消息到 chrome.runtime通信接口的轉換。


微信開發者工具擴展了 devtools 提供了 AppData 麵板,開發者可以修改裏麵數據然後直接看到 view 界麵的變化效果。這裏修改數據後 nwjs 會(hui) 將消息發送給 service 層,之後發生的事就跟上麵 4 5 6 步一樣:service 傳(chuan) 遞消息給 nwjs,最後到 view 層。


設計理念分析

小程序這樣的分層設計顯然是有意為(wei) 之的,它的中間層完全控製了程序對於(yu) 界麵進行的操作, 同時對於(yu) 傳(chuan) 遞的數據和響應時間也做到的監控。一方麵程序的行為(wei) 受到了極大限製, 另一方麵微信可以確保他們(men) 對於(yu) 小程序內(nei) 容和體(ti) 驗有絕對的控製。


我們(men) 在小程序的 js 代碼裏麵是不能直接使用瀏覽器提供的 DOM 和 BOM 接口的,這一方麵是因為(wei) js 代碼外層使用了局部變量進行屏蔽,另一方麵即便我們(men) 可以操作 DOM 和 BOM 接口,它們(men) 對應的 也是 service 模塊頁麵,並不會(hui) 對頁麵產(chan) 生影響。


這樣的結構也說明了小程序的動畫和繪圖 API 被設計成生成一個(ge) 最終對象而不是一步一步執行的樣子, 原因就是 json 格式的數據傳(chuan) 遞和解析相比與(yu) 原生 API 都是損耗不菲的,如果頻繁調用很可能損耗 過多性能,進而影響用戶體(ti) 驗。


理解了以上機製,再對 view 模塊和 service 模塊的 WeixinJSBridge 加以改造,我們(men) 便不難做到讓 小程序跑在自己的環境下,這樣就可以做些手機調試以及單頁麵測試等操作。

Kaiyun体育官方全站入口服務SERVICE
谘詢
微信掃碼谘詢
電話谘詢
400-888-9358