從源碼看瀏覽器彈窗消息機制:SetDefaultView 的創建、消息轉發與本地/在線頁通用實踐

引言

在現代瀏覽器的開發中,前端頁面和 C++ 內核之間的通信是一項核心功能。無論是本地設置頁(chrome:// 內置 H5)還是在線活動頁,前端都可能需要調用瀏覽器底層 API,實現諸如“設置默認瀏覽器”、“更改壁紙”、“讀取用戶配置”等操作。

本文將以 Chromium 內核及其派生瀏覽器為例,詳細解析 SetDefaultView 的創建、OnAppCmd 消息轉發機制以及 delegate 承載業務邏輯的設計思路,并討論這種機制在本地頁和在線頁的通用性。


一、SetDefaultView 的創建與初始化

瀏覽器彈窗(如“設置默認瀏覽器”對話框)通常是一個獨立的 View 對象,承載前端頁面并接收消息。核心創建入口是 SetDefaultView::CreateSetDefaultView

SetDefaultView* SetDefaultView::CreateSetDefaultView( gfx::NativeWindow parent, const GURL& url, Delegate* delegate, Browser* browser) { Browser* browser_active = BrowserList::GetInstance()->GetLastActive(); if (!browser_active) browser_active = browser; gfx::NativeWindow parent_active = parent; SeBrowserView* browser_view_active = SeBrowserView::GetBrowserViewForBrowser(browser_active); if (browser_view_active) parent_active = browser_view_active->frame()->GetNativeWindow(); SetDefaultView* set_view = new SetDefaultView(url, browser_active, delegate, true); if (nullptr == set_view) return nullptr; set_view->set_parent_window(parent_active); set_view->SetBrowserView(browser_view_active); set_view->set_use_focusless(true); set_view->set_close_on_deactivate(false); views::SeBubbleDelegateView::CreateBubble(set_view); return set_view; } 

關鍵解析

  1. 選擇活躍 Browser
    使用 BrowserList::GetInstance()->GetLastActive() 獲取當前活躍的瀏覽器實例,如果沒有,則使用傳入的 browser
    這樣彈窗總能掛載到一個活躍瀏覽器上下文。

  2. 確定父窗口
    利用 SeBrowserView::GetBrowserViewForBrowser 獲取 BrowserView,并將其 Frame 的原生窗口作為父窗口。
    父窗口的存在保證彈窗能正確附著在瀏覽器 UI 上。

  3. 實例化 SetDefaultView

    new SetDefaultView(url, browser_active, delegate, true); 
    • url:要加載的頁面,可以是本地頁或在線頁。

    • delegate:后端業務邏輯的承載者。

  4. 配置 View 屬性

    • set_use_focusless(true):無焦點模式。

    • set_close_on_deactivate(false):失去焦點不關閉。
      這些屬性保證彈窗在用戶操作時穩定顯示。

  5. 注冊 Bubble

    views::SeBubbleDelegateView::CreateBubble(set_view); 

    這一行是關鍵,它將 SetDefaultView 掛載到 UI 樹中,同時初始化內部 WebHostView,確保前端 JS 能發消息到后端 C++。


二、JS 消息到 C++ 的轉發機制

SetDefaultView 中,核心消息入口是 OnAppCmd

void SetDefaultView::OnAppCmd(WebHostView* sender, int invoke_id, const std::string& module_name, const std::string& function_name, const std::string& p1, const std::string& p2) { if (delegate_) delegate_->OnAppCmd(invoke_id, function_name, p1, p2); } 

調用流程解析

  1. 前端 JS 發起調用
    頁面中 JS 調用 appcmd(...)window.external.invoke(...),傳入函數名和參數:

appcmd("defaultModule", "setAsDefaultBrowser", "", ""); 
  1. WebHostView 接收消息
    WebHostView 負責攔截前端調用,將參數解析成:

    • invoke_id:調用 ID

    • module_name:模塊名

    • function_name:函數名

    • p1p2:參數

  2. SetDefaultView::OnAppCmd 轉發
    消息到達 OnAppCmd,但這里并不處理具體業務,而是轉發給 delegate。

  3. delegate 處理業務
    delegate_->OnAppCmd(...) 根據 function_name 執行具體邏輯,例如調用系統 API 設置默認瀏覽器或查詢狀態。


三、Delegate 的業務邏輯實現示例

典型的 delegate 實現如下:

class SetDefaultController : public SetDefaultView::Delegate { public: void OnAppCmd(int invoke_id, const std::string& function_name, const std::string& p1, const std::string& p2) override { if (function_name == "setAsDefaultBrowser") { HandleSetAsDefaultBrowser(invoke_id); } else if (function_name == "checkDefaultBrowser") { HandleCheckDefaultBrowser(invoke_id); } else { LOG(WARNING) << "Unknown command: " << function_name; } } private: void HandleSetAsDefaultBrowser(int invoke_id) { bool success = ShellIntegration::SetAsDefaultBrowser(); SendResponseToJs(invoke_id, success ? "ok" : "fail"); } void HandleCheckDefaultBrowser(int invoke_id) { bool is_default = ShellIntegration::IsDefaultBrowser(); SendResponseToJs(invoke_id, is_default ? "yes" : "no"); } void SendResponseToJs(int invoke_id, const std::string& result) { base::Value::Dict dict; dict.Set("id", invoke_id); dict.Set("result", result); web_ui()->CallJavascriptFunctionUnsafe("onAppCmdResponse", dict); } }; 

說明

  • delegate 根據 function_name 分發不同業務邏輯。

  • 執行業務后通過 web_ui()->CallJavascriptFunctionUnsafe 回調前端,完成 JS 的響應。


四、調用鏈總結

完整流程如下:

前端 JS ↓ appcmd / window.external.invoke WebHostView ↓ SetDefaultView::OnAppCmd ↓ delegate_->OnAppCmd ↓ 系統 API 或業務邏輯 ↓ WebUI 回調前端顯示結果 

五、本地頁與在線頁的適用性

1. 本地頁(chrome:// 或內置 H5)

  • URLchrome://settingspak 中的 H5 頁面

  • 優點

    • 響應快,無網絡依賴

    • 前端與后端接口完全可控

  • 應用場景

    • 設置默認瀏覽器

    • 修改瀏覽器主題

    • 內置配置頁

2. 在線頁(https:// 或遠程 H5)

  • URL:遠程服務器托管頁面

  • 優點

    • UI 可熱更新

    • 可以進行動態內容、A/B 測試

  • 應用場景

    • 登錄/綁定頁

    • 活動推廣頁

    • 數據統計/上報

  • 注意

    • 依賴網絡,安全性需校驗

    • 消息仍通過 OnAppCmd 轉發,不受 URL 來源影響

3. 通用性分析

  • 核心機制只依賴 WebHostView + OnAppCmd + delegate

  • 不論頁面來源本地還是遠程,前端調用均可安全到達 delegate 執行邏輯


六、總結

  1. SetDefaultView 是瀏覽器彈窗消息通道的承載者。

  2. CreateSetDefaultView 負責實例化 view、掛載 UI、初始化 WebHostView。

  3. OnAppCmd 作為 JS 消息入口,負責轉發給 delegate。

  4. delegate 承載業務邏輯,實現真正的功能操作。

  5. 本地頁和在線頁都可使用同一機制,差別只在頁面 URL 和資源管理。

這種設計具有以下優點:

  • UI 與業務邏輯解耦

  • 消息分發統一,可擴展性強

  • 支持本地和在線頁面,便于前端迭代


七、附錄:博客擴展建議

  1. 源碼截圖:展示 CreateSetDefaultViewOnAppCmd、delegate 代碼片段

  2. 調用鏈圖:前端 JS → WebHostView → SetDefaultView → delegate → 系統 API

  3. 實際案例:設置默認瀏覽器、壁紙設置頁面

  4. 注意事項

    • delegate 必須在 view 創建前綁定

    • 在線頁調用需要考慮跨域和安全

    • 失去焦點或父窗口關閉時的行為設置


通過本文,你可以清晰理解瀏覽器彈窗從創建到 JS 消息處理的完整閉環,無論本地頁還是在線頁,都能使用同樣的機制實現前端調用本地業務邏輯。

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

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

相關文章

對比視頻處理單元(VPU)、圖形處理器(GPU)與中央處理器(CPU)

如今選擇互聯網點播流媒體與直播視頻的用戶數量已遠超傳統廣播電視&#xff0c;這一轉變催生了對高性能媒體轉碼與OTT流媒體功能專用技術的需求。 我們最新推出的Accelerated Compute云計算解決方案&#xff0c;首次通過NETINT Quadra視頻處理單元&#xff08;VPU&#xff09;…

vue3寫一個簡單的時間軸組件

插件版本&#xff1a;"element-plus": "^2.3.12""vue": "^3.0.0"代碼示例&#xff1a;樣式文件style.less&#xff1a;改變el-tooltip樣式&#xff0c;可以復制代碼到公共樣式文件.el-popper.o-el-tooltip-popper-class {max-width: 3…

Linex系統網絡管理(二)

二、網絡連接查看1. netstat作用查看本地服務的網絡監聽狀態查看客戶端連接到本地服務的連接狀態語法&#xff1a;netstat 選項 &#xff08;-anptu&#xff09;選項作用-n&#xff0c; --numeric顯示數字形式地址而不是去解析主機、端口或用戶名-a, --all顯示所有的監聽或連接…

Unity MQTT通訊

首先明確概念&#xff0c;什么是MQTT&#xff1f; MQTT是一種輕量級、基于發布 / 訂閱&#xff08;Publish/Subscribe&#xff09;模式的物聯網&#xff08;IoT&#xff09;通信協議&#xff0c;在帶寬有限、網絡不穩定的環境下&#xff0c;實現低功耗、低延遲的設備間通信&am…

JavaSE:類和對象2

一、封裝封裝的概念面向對象程序三大特性&#xff1a;封裝、繼承、多態。而類和對象階段&#xff0c;主要研究的就是封裝特性。何為封裝呢&#xff1f;簡單來說 就是套殼屏蔽細節。例如手機&#xff0c;你看不到任何的內部實現細節&#xff0c;只留下一些公開的接口給你使用&am…

RandAR訓練自己的數據集

論文題目:RandAR: Decoder-only Autoregressive Visual Generation in Random Orders(隨機順序下僅解碼器的自回歸視覺生成) 會議:CVPR2025 摘要:我們介紹了RandAR,一種僅解碼器的視覺自回歸(AR)模型,能夠以任意令牌順序生成圖像。與之前依賴于預定義生成順序的純解碼器…

基于PHP服裝租賃管理系統/基于php的服裝管理系統的設計與實現

基于PHP服裝租賃管理系統/基于php的服裝管理系統的設計與實現

高并發內存池(12)-ThreadCache回收內存

高并發內存池&#xff08;12&#xff09;-ThreadCache回收內存 代碼如下&#xff1a; // 釋放對象時&#xff0c;鏈表過長時&#xff0c;回收內存回到中心緩存 void ThreadCache::ListTooLong(FreeList& list, size_t size) {void* start nullptr;void* end nullptr;list…

讀大語言模型09超級智能

1. 超級智能1.1. 如果人工智能超越人類智能&#xff0c;可能會成為人類存在的一個重大威脅1.1.1. 對超級人工智能潛在危險最為擔憂的群體中&#xff0c;恰恰包括那些否認大語言模型具備真正智能的人1.2. 計算機科學已經成為所有科學領域中不可或缺的重要組成部1.3. GPT具備編寫…

阿里云拉取dockers鏡像

假如你已經在云服務器上安裝了docker需要配置下docker鏡像加速代理就行了找到自己的加速網址&#xff1a;然后在云服務器上&#xff0c;修改docker 配置文件&#xff0c;vi /etc/docker/daemon.json沒有這個文件的話&#xff0c;需要創建一個。{"default-address-pools&qu…

python自學筆記14 NumPy 線性代數

在Numpy庫中有專門的linalg 模塊用來做線性代數相關的運算。 本文中線性代數的一般概念不會解釋 拆解矩陣 鳶尾花數據矩陣結構如下&#xff08;150 4&#xff09;&#xff1a;取其中的行向量和列向量&#xff1a; # 導入包 import numpy as np from sklearn.datasets import l…

ubuntu20搭建MQTT

sudo apt update sudo apt install mosquitto mosquitto-clients sudo mosquitto_passwd -c /etc/mosquitto/passwd myuser sudo nano /etc/mosquitto/mosquitto.conf# 允許匿名用戶連接&#xff08;默認為 true&#xff0c;我們先關閉它&#xff09; allow_anonymous false# 指…

云服務器的主要用途都有哪些?

企業可以利用云服務器構建官方網站&#xff0c;企業官網需要穩定的運行環境來展示產品、服務、公司動態等信息&#xff0c;云服務器提供的高可用性和可擴展性&#xff0c;能保障大量用戶同時訪問時網站的穩定運行。移動應用的后端服務可以部署在云服務器上&#xff0c;如社交類…

IntelliJ IDEA Debug 模式功能指南

文章目錄前言&#x1f4a1; 1. 斷點類型與設置&#x1f680; 2. 啟動 Debug 模式?? 3. 調試控制按鈕詳解&#x1f440; 4. 查看與監控變量&#x1f9f0; 5. 高級調試技巧&#x1f48e; 總結前言 作為一名 Java 開發者&#xff0c;熟練掌握調試技巧是提高開發效率的關鍵。Int…

在pycharmIDE中如何快速掌握一個新模塊的使用方法

一、文檔使用懸停文檔&#xff1a;鼠標懸停在模塊/函數上顯示文檔摘要 (?最常用)快速文檔&#xff1a;選中標識符按 CtrlQ (Windows/Linux) 或 F1 (Mac)跳轉定義&#xff1a;Ctrl左鍵單擊 直接跳轉到源碼定義處 (?最權威)參數提示&#xff1a;輸入函數名時自動顯示參數列表&a…

win11自定義停止更新方法

一、打開運行窗口&#xff08;winr&#xff09;輸入regedit打開注冊表編輯器。按照如下路徑尋找。計算機\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings二、在Settings頁面下右擊——>新建——>DWORD(32位)值(D)&#xff0c;并重命名為粉色框中的名字…

Unity委托、匿名方法與事件深度解析:從理論到實戰

Unity委托、匿名方法與事件深度解析&#xff1a;從理論到實戰 摘要&#xff1a;本文深入剖析Unity中委托、匿名方法與事件的核心機制&#xff0c;結合理論框架與實戰案例&#xff0c;幫助開發者掌握高效的事件驅動編程技巧。全文包含12個代碼片段及6個核心原理圖示框架&#x…

大腦的藏寶圖——神經科學如何為自然語言處理(NLP)的深度語義理解繪制新航線

摘要&#xff1a; 截至2025年&#xff0c;大型語言模型&#xff08;LLM&#xff09;已展現出驚人的能力&#xff0c;但其內在的“黑箱”特性和對深層語義理解的局限性也日益凸顯。本報告旨在深入探討一個充滿潛力的前沿交叉領域&#xff1a;借鑒地球上最古老、最精密的語言處理…

記錄使用ruoyi-flowable開發部署中出現的問題以及解決方法(二)

1.vform的使用與傳值 使用動態表單&#xff0c;把當前的用戶名傳值進動態表單&#xff0c;另外動態表單的上傳組件成功后傳值會父組件。 在父組件的加載函數中增加&#xff1a; mounted(){this.$refs.vFormRef.addEC("getuploadfile",this);},該方法為給表單加載外…

Apifox 8 月更新|新增測試用例、支持自定義請求示例代碼、提升導入/導出 OpenAPI/Swagger 數據的兼容性

Apifox 作為全能 API 工具&#xff0c;正以迅猛之勢革新開發者的工作方式&#xff01;想象一下&#xff0c;您正為測試用例編寫頭疼&#xff0c;或因 OpenAPI 文件導入失敗而延誤項目&#xff0c;而 Apifox 8 月更新卻帶來“救命稻草”&#xff1a;新增測試用例功能、自定義請求…