疏通經脈: Bridge 聯通邏輯層和渲染層

本節概述

經過前面兩節的開發,我們已經完成了小程序邏輯線程和 UI 線程的啟動引擎準備,這節開始,我們將完善 native bridge 層的搭建,構建起邏輯線程和UI線程之間的橋梁。

開始之前我們先來回顧一下邏輯引擎小節相關的流程圖:

在這里插入圖片描述

一次小程序的啟動過程,我們在創建好小程序的 邏輯引擎worker 和 繪制引擎webview 之后,從啟動到渲染依次會經過:

  1. 通知 webview 加載小程序資源,如果是首次啟動,還需要通知邏輯線程加載資源(非首次啟動則不用,一個小程序的邏輯 worker 層是公用的)
  2. 資源加載完畢后,開始通知邏輯線程創建應用實例
  3. 實例初始化完畢,請求 worker 線程獲取小程序初始化渲染數據
  4. bridge 將worker層獲取到的初始化數據發送給ui線程,ui線程啟動渲染
  5. ui渲染完畢通過bridge 通知給邏輯worker,觸發小程序的生命周期函數

在前面的雙線程結構的小節中,我們已經完成了前置的: 創建worker創建webview 的準備。現在我們繼續在其基礎上連接起邏輯線程引擎ui線程引擎,打通經脈,啟動小程序渲染

環境準備

在開始之前,我們先在之前小節的基礎上調整下代碼環境: 當時我們創建 webview 的時候,是模擬的小程序的配置信息。現在我們來模擬一個小程序的配置文件,然后通過網絡請求讀取配置信息后再注入

先創建一個小程序的編譯后的配置文件,放在public目錄下方便直接通過服務加載:

// config.json,這個配置文件的內容也是和我們上兩節模擬的小程序邏輯代碼和頁面代碼一致對應的
{"app": {"entryPagePath": "pages/home/index","pages": ["pages/home/index"],"window": {"navigationBarBackgroundColor": "#ffffff","navigationBarTextStyle": "black","navigationBarTitleText": "微信接口功能演示","backgroundColor": "#eeeeee"},"tabBar": [],"networkTimeout": {},"debug": true},"modules": {"pages/home/index": {"navigationBarBackgroundColor": "#ffd200","navigationBarTextStyle": "black","navigationBarTitleText": "美團","backgroundColor": "#fff","usingComponents": {}}}
}

src/native/miniApp.ts 文件夾下的 init 方法中,我們進行下調整:

async init() {// 模擬讀取小程序配置文件信息
+ const configPath = `/${this.app.appId}/config.json`;
+ const res = await fetch(configPath).then(res => res.text());
+ this.appConfig = JSON.parse(res);// 獲取小程序入口文件配置: 傳入的path 或者 配置文件中的 entryPagePath
+ const entryPagePath = this.app.path || this.appConfig!.app.entryPagePath;// 入口頁面對應的頁面配置信息
+ const pageConfig = this.appConfig!.modules?.[entryPagePath];const entryPageBridge = await this.createBridge({jscore: this.jscore,isRoot: true,appId: this.app.appId,pagePath: this.app.path,pages: this.appConfig!.app?.pages,query: this.app.query,scene: this.app.scene,configInfo: mergePageConfig(this.appConfig!.app, pageConfig), // 合并配置信息,主要是頁面配置和全局window配置信息的合并});
}
export function mergePageConfig(appConfig: Record<string, any>, pageConfig: Record<string, any>) {const result: Record<string, any> = {};const appWindowConfig = appConfig.window || {}; // 全局window配置信息const pagePrivateConfig = pageConfig || {};     // 頁面對應的配置信息result.navigationBarTitleText = pagePrivateConfig.navigationBarTitleText || appWindowConfig.navigationBarTitleText || '';result.navigationBarBackgroundColor = pagePrivateConfig.navigationBarBackgroundColor || appWindowConfig.navigationBarBackgroundColor || '#000';result.navigationBarTextStyle = pagePrivateConfig.navigationBarTextStyle || appWindowConfig.navigationBarTextStyle || 'white';result.backgroundColor = pagePrivateConfig.backgroundColor || appWindowConfig.backgroundColor || '#fff';result.navigationStyle = pagePrivateConfig.navigationStyle || appWindowConfig.navigationStyle || 'default';return result;
}

完善webview消息通信

在前面實現webview管理模塊的時候,我們預留了消息通信相關的實現,經過上一小節 UI 引擎的實現我們可以知道,bridge 側和ui線程的通信我們直接通過掛載ui全局window上的 JSBridge 對象來完成。bridge 側需要添加 onReceiveUIMessage API給ui線程側調用,來發送消息到bridge 側

src/native/webview/index.ts 文件中我們來完善通信的邏輯;

async init(callback: () => void) {// 等待frame 加載完成await this.frameLoaded();const iframeWindow = window.frames[this.iframe.name];// 給webview內部的JSBridge對象添加 onReceiveUIMessage 方法iframeWindow.JSBridge.onReceiveUIMessage = (message: IMessage) => {this.event.emit('message', message);}callback && callback();
}postMessage(message: IMessage) {const iframeWindow = (window.frames as any)[this.iframe.name];if (iframeWindow) {// 觸發webview內部 JSBridge對象上的 onReceiveNativeMessage 方法完成通信iframeWindow.JSBridge.onReceiveNativeMessage(message);}
}

啟動頁面渲染

從上面分析的流程中我們可以發現,啟動過程的觸發點只需要通知兩個線程加載資源即可,后續的過程將有兩個線程的消息來持續推進。

現在我們來實現一個啟動渲染的方法,開始讓兩個線程工作:

// src/native/bridge/index.ts
/*** bridge 通知邏輯線程和UI線程加載小程序資源*/
start(loadLogicSource = true) {// 通知UI線程加載資源this.webview?.postMessage({type: 'loadResource',body: {appId: this.opts.appId,pagePath: this.opts.pagePath,}});// 初始化觸發一次小程序邏輯資源加載if (loadLogicSource) {this.jscore.postMessage({type: 'loadResource',body: {appId: this.opts.appId,bridgeId: this.id,pages: this.opts.pages,}});} else {this.status++;}
}

這里有個參數是是否需要邏輯線程加載資源,經過前面小節的介紹其實我們可以快速的知道,因為一個小程序的邏輯線程worker是公用的,在初次啟動后,后面就可以不用再繼續加載了。

同時邏輯中還有一個 status 字段,這個狀態字段是用于判斷小程序進行到哪一步了,是否可以進行某一個等;

比如小程序要啟動創建App實例,就需要兩側線程的資源都加載準備完畢,此時 status 的狀態就需要變到 2 才能繼續往下進行(ui線程資源加載完畢+1 和 邏輯線程資源加載完畢+1)

現在啟動的契機開始之后,后續就是完成bridge監聽兩側線程的消息,來推進邏輯的渲染:

邏輯線程消息監聽

邏輯線程的啟動事件通知包括:

  • logicResourceLoaded 邏輯線程資源加載完畢,如果此時 status 為 2,及ui側也完畢時,啟動App實例創建
  • appIsCreated 邏輯線程App創建完畢,后面要開始通知邏輯線程初始化渲染數據
  • initialDataReady 初始化渲染數據創建完畢返回,bridge 要通知 ui 線程掛載頁面了
  • updateModule 邏輯線程側調用了 setData api更新了數據,需要把新的數據發送個ui線程重新渲染
jscoreMessageHandler(message: IMessage) {console.log('接收到來自于邏輯線程的消息: ', message);const { type, body } = message;// 判斷 bridgeId 是否對應if (body.bridgeId !== this.id) return;switch (type) {case 'logicResourceLoaded':this.status++;this.createApp(); // 邏輯線程和UI準備好之后就可以開始創建App了break;case 'appIsCreated':this.status++;this.notifyMakeInitialData(); // 通知邏輯線程初始化小程序渲染數據break;case 'initialDataReady':this.status++;this.setInitialData(body); // 把邏輯線程的初始化數據設置給UI線程,UI線程開始渲染頁面break;case 'updateModule':this.updateModule(body); // 邏輯線程調用setData 更新數據,通知UI渲染}
}// 通知邏輯線程創建小程序App實例
createApp() {// 只有logic和ui線程的loadResource 都完畢后,才能開始創建,此時status會變成2if (this.status !== 2) return;this.jscore.postMessage({type: 'createApp',body: {bridgeId: this.id,scene: this.opts.scene,pagePath: this.opts.pagePath,query: this.opts.query,}});
}
// 通知邏輯線程初始化渲染數據
notifyMakeInitialData() {this.jscore.postMessage({type: 'makePageInitialData',body: {bridgeId: this.id,pagePath: this.opts.pagePath,}});
}
// 將邏輯線程初始化好的渲染數據發送給ui線程渲染頁面
setInitialData(data) {const { initialData } = data;this.webview?.postMessage({type: 'setInitialData',body: {initialData,bridgeId: this.id,pagePath: this.opts.pagePath,}});
}
// 邏輯線程數據更新,通知ui線程重新渲染
updateModule(payload) {const { id, data } = payload;this.webview?.postMessage({type: 'updateModule',body: {id,data,}})
}
UI 線程啟動消息處理

ui 線程啟動過程主要包括的事件節點有:

  • uiResourceLoaded ui線程資源加載完畢,如果 status 為2,及邏輯線程也加載完畢,可以啟動創建 App 實例
  • moduleCreated ui線程模塊創建完畢(在繪制過程了),此時需要通知邏輯線程創建頁面實例 PageModule
  • moduleMounted ui線程頁面已經掛載好了,此時通知邏輯線程觸發 ready 事件
  • triggerEvent ui線程事件交互,通知邏輯線程觸發相應的處理函數
uiMessageHandler(message: IMessage) {console.log('接收到來自UI線程的消息: ', message);const { type, body } = message;switch (type) {case 'uiResourceLoaded':this.status++;this.createApp();break;case 'moduleCreated':this.uiInstanceCreated(body);break;case 'moduleMounted':this.uiInstanceMounted(body);break;case 'triggerEvent':this.triggerEvent(body);break;}
}
// ui線程模塊創建好,通知邏輯線程可以創建頁面實例了
// 這里后面真實觸發的時機回調整為 vue created 狀態時執行
uiInstanceCreated(payload) {const { path, id } = payload;this.jscore.postMessage({type: 'createInstance',body: {id,path,bridgeId: this.id,query: this.opts.query,}});
}
// ui掛載完畢,通知邏輯線程觸發 ready
uiInstanceMounted(payload) {const { id } = payload;this.jscore.postMessage({type: 'moduleMounted',body: { id }});
}
// 用戶事件,通知邏輯線程觸發處理函數
triggerEvent(payload) {const { id, methodName, paramsList } = payload;this.jscore.postMessage({type: 'triggerEvent',body: {id,methodName,paramsList}})
}

經過上面的步驟之后,我們的啟動過程就連接好了,此時運行項目點擊美團小程序可以看到如下效果:

錄屏2025-06-29 18.05.39

本小節的代碼已發布至github倉庫,可前往查看完整代碼: mini-wx-app

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87034.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87034.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87034.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【攻防篇】解決:阿里云docker 容器中自動啟動xmrig挖礦

解決&#xff1a;阿里云服務器docker容器被植入挖礦程序 **1. 緊急處理&#xff1a;停止挖礦進程****&#xff08;1&#xff09;查找并終止 xmrig 進程****&#xff08;2&#xff09;刪除惡意文件** **2. 清理被感染的容器****&#xff08;1&#xff09;停止并刪除容器****&…

對稱非對稱加密,https和http,https通訊原理,Charles抓包原理

文章目錄 對稱加密的非對稱加密http和https原理TCP三次握手四次揮手https通訊流程&#xff1a;Charles抓包原理 對稱加密的非對稱加密 對稱加密&#xff1a;發送方的接收方式使用同一個秘鑰進行加密和解密&#xff0c;發送方將需要發送的數據&#xff0c;選擇某種加密算法&…

Kubernetes(K8s)_15_調度原理

文章目錄 Pod調度實現原理調度隊列優先隊列底層數據 調度緩存調度框架 Pod調度 Pod調度: 通過污點、容忍度和親和性影響Pod的調度 調度器實現, 其基于配置器構造(其配置來源于配置API)調度過程中任何插件返回拒絕, 都會導致Pod可能再次返回調度隊列 如: Pod調度簡略流程 調度…

moduo之tcp客戶端TcpClient

結構 #mermaid-svg-muvN6eOMXA4rCyXP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-muvN6eOMXA4rCyXP .error-icon{fill:#552222;}#mermaid-svg-muvN6eOMXA4rCyXP .error-text{fill:#552222;stroke:#552222;}#merm…

中國科技術語雜志中國科技術語雜志社中國科技術語編輯部2025年第3期目錄

理論研究 認知術語學與社會認知術語學比較研究 吳小芳; 3-11 大語言模型背景下的術語翻譯研究&#xff1a;現狀、問題與展望 朱玉彬;王梓; 12-20 航空事件謠言敘事中的術語初探 劉成盼;劉東亮; 21-28 定名研討 淺談訓詁、訓詁學和訓詁學術語 林童; 29-35 …

自然語言處理NLP期末復習

目錄 第一章1. NLP的基本過程包括哪些-自然語言處理面臨的困難是什么2. 自然語言處理算法定義&#xff0c;過程和應用3. 結合自己的研究-描述研究中涉及的自然語言處理模型或算法&#xff0c;模型或算法原理&#xff0c;具體的處理過程4. 自然語言處理的的兩大核心任務是5. 程序…

單片機 - STM32F103“復用功能重映射”完整解析:從JTAG釋放到TIM重映射實戰詳解

本文將詳細講解 STM32F103 系列中常見的“復用功能重映射”&#xff08;Remap&#xff09;機制&#xff0c;包括 JTAG 占用、引腳默認功能與復用功能的關系&#xff0c;以及如何通過寄存器或標準庫代碼實現重映射。以 TIM3 在 PB4/PB5 上輸出 PWM 為例&#xff0c;進行實戰講解…

【C語言】知識總結·內存函數

目錄 前言&#xff1a; 一、內存復制函數 1. memcpy - 內存塊復制 2. memmove - 內存塊移動 二、內存設置函數 1. memset - 內存塊填充 三、內存比較函數 1. memcmp 2.memchr 三內存分配函數 1 .malloc 2.free 總結&#xff1a; 注意事項&#xff1a; 前言&…

python+uniapp基于微信小程序面向品牌會員的在線商城系統

文章目錄 具體實現截圖本項目支持的技術路線源碼獲取詳細視頻演示&#xff1a;文章底部獲取博主聯系方式&#xff01;&#xff01;&#xff01;&#xff01;本系統開發思路進度安排及各階段主要任務java類核心代碼部分展示主要參考文獻&#xff1a;源碼獲取/詳細視頻演示 ##項目…

小魚fish系統 sudo apt update報錯(密鑰失效)

在使用小魚fish提供的系統鏡像文件&#xff0c;sudo apt update系統更新時遇到了以下報錯&#xff0c;即ROS 2 倉庫的 GPG 密鑰已過期&#xff0c;以及 Docker 倉庫使用了過時的密鑰存儲方式 fishrosfishros-linux:~$ sudo apt update 獲取:1 http://mirrors.tuna.tsinghua.ed…

深度優先搜索 (DFS) 詳解

1. 什么是深度優先搜索&#xff1f; 深度優先搜索&#xff08;Depth-First Search, DFS&#xff09;是一種用于遍歷或搜索樹或圖的算法。這個算法會盡可能深地搜索樹的分支。當節點v的所在邊都已被探尋過&#xff0c;搜索將回溯到發現節點v的那條邊的起始節點。這一過程一直進…

文心4.5開源大模型的使用和部署

前言 就在今天&#xff0c;文心4.5模型開源了&#xff0c;不是一個&#xff0c;而是整個系列模型正式開源。很突然&#xff0c;我都震驚了。文心4.5系列開源模型共10款&#xff0c;涵蓋了激活參數規模分別為47B 和3B 的混合專家&#xff08;MoE&#xff09;模型&#xff08;最…

HarmonyOs開發之——TypeScript介紹、入門,及 TypeScript、JavaScript、ArkTs的具體區別解讀。

HarmonyOs開發之——TypeScript介紹、入門&#xff0c;及 TypeScript、JavaScript、ArkTs的具體區別解讀。 一、 開發語言介紹&#xff1a; TypeScript是JavaScript的超集&#xff0c;ArkTS則是TypeScript的超集。ArkTs是 HarmonyOs的主力開發語言&#xff0c;它在TypeScript…

《JMS事務性會話徹底解析:消息監聽中的 commit、rollback 和冪等設計》

大家好&#xff0c;我是G探險者&#xff01; &#x1f4cc; 場景引入 在實際項目中&#xff0c;我們常常面臨以下挑戰&#xff1a; 監聽 MQ 消息失敗了&#xff0c;希望自動重試&#xff1f;消費 MQ 消息后&#xff0c;要寫數據庫&#xff0c;但中間報錯了&#xff1f;消息處…

vue3 el-table 列增加 自定義排序邏輯

在 Vue 3 中使用 Element Plus 的 <el-table> 組件時&#xff0c;如果你想增加自定義排序邏輯&#xff0c;可以通過以下幾個步驟實現&#xff1a; 1. 使用 default-sort 屬性 首先&#xff0c;你可以在 <el-table> 組件上使用 default-sort 屬性來指定默認的排序…

ISP Pipeline(7): Gamma Correction 伽馬校正

AI_Plays/ISP/Fast_ISP_Progress.ipynb at main ameengee/AI_Plays GitHub Gamma Correction&#xff08;伽馬校正&#xff09;是圖像處理中的一個重要步驟&#xff0c;目的是調整圖像的亮度&#xff0c;使其更符合人眼的感知或顯示設備的特性。 為什么需要 Gamma Correcti…

AI提取伴奏,實現卡拉OK效果 —— 「suno api/luno api/kuka api」

導讀 喜歡唱歌&#xff0c;卻總苦于找不到純凈的伴奏&#xff1f;或者你想把喜歡的歌曲翻唱一遍&#xff0c;卻被人聲干擾搞得頭大&#xff1f;現在&#xff0c;AI技術已經悄悄解決了這個問題。借助AI智能工具&#xff0c;你可以輕松提取任何一首歌的伴奏&#xff0c;享受宛如…

pip介紹

pip是什么&#xff1f; pip&#xff08;Pip Installs Packages&#xff09;是Python的官方管理工具&#xff0c;用于安裝、升級、卸載和管理Python第三方庫及其依賴關系。它是Python生態系統的核心組件&#xff0c;通過連接PyPI&#xff08;Python Package Index&#xff09;這…

機器學習20-線性網絡思考

機器學習20-線性網絡思考 針對線性網絡的基礎問題&#xff0c;使用基礎示例進行解釋 1-核心知識點 1-線性模型家族的線性回歸和邏輯回歸分別是什么&#xff0c;線性模型家族還有沒有其他的模型 線性模型家族是一系列基于線性假設的統計模型&#xff0c;它們假設因變量和自變量…

【科研繪圖系列】R語言繪制世界地圖分布(world map)

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹加載R包數據下載導入數據數據預處理準備畫圖畫圖總結系統信息介紹 本教程旨在通過R語言及其相關地理空間分析包,展示如何對環境數據進行空間聚類分析,并將結果可視化。教程從讀…