本机端和 Web 端代码的互操作

Microsoft Edge WebView2 控件允许将 Web 内容嵌入本机应用程序。 可以根据需要完成的任务,以不同的方式使用 WebView2。 本文介绍如何使用简单消息、JavaScript 代码和本机对象进行通信。

一些常见用例包括:

  • 导航到其他网站后,更新本机主机窗口标题。
  • 从 Web 应用发送本机相机对象并使用其方法。
  • 在应用程序的 Web 端运行专用 JavaScript 文件。

开始之前

本教程逐步讲解示例应用代码,以演示 WebView2 中的一些通信功能。 克隆 WebView2Samples 存储库,在 Visual Studio 中打开文件 .sln ,生成项目,并运行 (调试) ,以按照本文中的步骤进行操作。

有关克隆存储库的详细步骤,请参阅 WebView2 示例

方案:简单消息传送

WebView2 控件允许在应用程序的 Web 端和本机端之间交换简单的消息。 可以使用 或 等JSONString数据类型在主机应用程序和 WebView2 之间发送消息。

将消息从主机应用发送到 WebView2

此示例显示示例应用如何根据主机应用中的消息更改前端文本的颜色。

若要查看消息传送的运行情况::

  1. 运行示例应用,然后选择“ 方案 ”选项卡,然后选择“ Web 消息” 选项。

    将显示以下屏幕:

    Web 消息示例页,其中演示了主机应用与 WebView2 实例之间使用 Web 消息的基本交互

  2. 请注意第一部分,标题为 Posting Messages。 按照说明操作,然后选择“编写消息发布 JSON 脚本>”。 单击" 确定"。 消息变为蓝色:

    “发布 Web 消息 JSON”演示

    我们如何能够更改文本颜色? 此示例首先在本机端创建按钮。 然后,该示例添加以下代码,以在单击按钮时发布 Web 消息。 此代码将 Web 文本的颜色更改为蓝色。

    该示例包含用于创建在单击时调用 SendJsonWebMessage() 的 Windows 按钮的 C++ 代码。

    有关使用 C++ 创建按钮的详细信息,请参阅 如何创建按钮

  3. 单击按钮时,它会从 ScriptComponent.cpp 调用以下代码。

    // Prompt the user for some JSON and then post it as a web message.
    void ScriptComponent::SendJsonWebMessage()
    {
        TextInputDialog dialog(
            m_appWindow->GetMainWindow(),
            L"Post Web Message JSON",
            L"Web message JSON:",
            L"Enter the web message as JSON.",
            L"{\"SetColor\":\"blue\"}");
        if (dialog.confirmed)
        {
            m_webView->PostWebMessageAsJson(dialog.input.c_str());
        }
    }
    

    注意

    本教程的其余部分使用 WebView2 示例中的文件 ScenarioWebMessage.html 。 在工作时比较自己的 HTML 文件,或从 ScenarioWebMessage.html复制并粘贴内容。

    该示例在 Web 上使用 JavaScript 事件侦听器。

  4. ScenarioWebMessage.html 标头中包含以下 JavaScript:

    window.chrome.webview.addEventListener('message', arg => {
       if ("SetColor" in arg.data) {
          document.getElementById("colorable").style.color = 
          arg.data.SetColor;
       }
    });
    

    事件侦听器 侦听 消息事件并使消息文本可着色。

  5. HTML 文件描述了消息传递练习:

    <h1>WebMessage sample page</h1>
    <p>This page demonstrates basic interaction between the host app 
    and the webview by means of Web Messages.</p>
    
    <h2>Posting Messages</h2>
    <p id="colorable">Messages can be posted from the host app to the 
    webview using the functions
    <code>ICoreWebView2::PostWebMessageAsJson</code> and
    <code>ICoreWebView2::PostWebMessageAsString</code>. Try selecting 
    the menu item "Script > Post Message JSON" to send the message 
    <code>{"SetColor":"blue"}</code>.
    It should change the text color of this paragraph.</p>
    
  6. 菜单Post Message JSON项位于生成的Microsoft Visual C++资源脚本文件 WebView2APISample.rc 中

    MENUITEM "Post Message JSON",           IDM_POST_WEB_MESSAGE_JSON
    
  7. 脚本文件反过来又调用 ScriptComponent.cpp 中的 事例IDM_POST_WEB_MESSAGE_JSON

    case IDM_POST_WEB_MESSAGE_JSON:
       SendJsonWebMessage();
       return true;
    

这完成了显示 WebView2 如何通过简单消息进行通信的示例。

通过 postMessage 接收消息字符串

此示例遵循 Receiving Messages 网页的 部分,以更改标题栏的文本。 主机应用从 WebView2 接收带有新标题栏文本的消息。

C++ 文件处理标题文本,并将其作为字符串传达给主机应用。

  1. 单击按钮时,WebView2 将使用 window.chrome.webview.postMessageScenarioWebMessage.html将消息从网页传输到本机应用程序。

    function SetTitleText() {
       let titleText = document.getElementById("title-text");
       window.chrome.webview.postMessage(`SetTitleText ${titleText.value}`);
    }
    
  2. HTML 文件包括一个文本框和按钮,用于向主机应用发送消息:

    <h2>Receiving Messages</h2>
    <p>The host app can receive messages by registering an event handler 
    with <code>ICoreWebView2::add_WebMessageReceived</code>. If you 
    enter text and click "Send", this page will send a message to the 
    host app which will change the text of the title bar.</p>
    <input type="text" id="title-text"/>
    <button onclick="SetTitleText()">Send</button>
    
  3. ScenarioWebMessage.cpp 中的事件处理程序处理新的标题文本字符串,并将其作为字符串传达给主机应用。

    // Setup the web message received event handler before navigating to
    // ensure we don't miss any messages.
    CHECK_FAILURE(m_webView->add_WebMessageReceived(
       Microsoft::WRL::Callback<ICoreWebView2WebMessageReceivedEventHandler>(
          [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args)
    {
       wil::unique_cotaskmem_string uri;
       CHECK_FAILURE(args->get_Source(&uri));
    
       // Always validate that the origin of the message is what you expect.
       if (uri.get() != m_sampleUri)
       {
          return S_OK;
       }
       wil::unique_cotaskmem_string messageRaw;
       CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw));
       std::wstring message = messageRaw.get();
    
       if (message.compare(0, 13, L"SetTitleText ") == 0)
       {
          m_appWindow->SetTitleText(message.substr(13).c_str());
       }
       else if (message.compare(L"GetWindowBounds") == 0)
       {
          RECT bounds = m_appWindow->GetWindowBounds();
          std::wstring reply =
                L"{\"WindowBounds\":\"Left:" + std::to_wstring(bounds.left)
                + L"\\nTop:" + std::to_wstring(bounds.top)
                + L"\\nRight:" + std::to_wstring(bounds.right)
                + L"\\nBottom:" + std::to_wstring(bounds.bottom)
                + L"\"}";
          CHECK_FAILURE(sender->PostWebMessageAsJson(reply.c_str()));
       }
       return S_OK;
    }).Get(), &m_webMessageReceivedToken));
    

往返消息

此示例遵循 <h2>Round trip</h2> WebMessage 示例页 的 部分,ScenarioWebMessage.html。 此示例显示从 WebView2 到主机应用并返回的往返消息。 主机应用接收来自 WebView2 的请求并返回活动窗口的边界。

当主机应用请求时,C++ 文件获取窗口边界,并将数据作为 JSON Web 消息发送到 WebView2。

  1. HTML 文件包含一个按钮,用于从主机应用获取窗口边界:

    <h2>Round trip</h2>
    <p>The host app can send messages back in response to received 
    messages. If you click the <b>Get window bounds</b> button, the 
    host app reports back the bounds of its window, which are 
    displayed in the text box.</p>
    <button onclick="GetWindowBounds()">Get window bounds</button><br>
    <textarea id="window-bounds" rows="4" readonly></textarea>
    
  2. 当用户单击按钮时,WebView2 使用 window.chrome.webview.postMessage将消息从网页传输到本机应用程序。

    function GetWindowBounds() {
       window.chrome.webview.postMessage("GetWindowBounds");
    }
    
  3. ScenarioWebMessage.cpp 中的事件处理程序获取窗口边界,并使用 将数据发送到主机应用TryGetWebMessageAsString

    // Setup the web message received event handler before navigating to
    // ensure we don't miss any messages.
    CHECK_FAILURE(m_webView->add_WebMessageReceived(
       Microsoft::WRL::Callback<ICoreWebView2WebMessageReceivedEventHandler>(
          [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args)
    {
       wil::unique_cotaskmem_string uri;
       CHECK_FAILURE(args->get_Source(&uri));
    
       // Always validate that the origin of the message is what you expect.
       if (uri.get() != m_sampleUri)
       {
          return S_OK;
       }
       wil::unique_cotaskmem_string messageRaw;
       CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw));
       std::wstring message = messageRaw.get();
    
       if (message.compare(0, 13, L"SetTitleText ") == 0)
       {
          m_appWindow->SetTitleText(message.substr(13).c_str());
       }
       else if (message.compare(L"GetWindowBounds") == 0)
       {
          RECT bounds = m_appWindow->GetWindowBounds();
          std::wstring reply =
                L"{\"WindowBounds\":\"Left:" + std::to_wstring(bounds.left)
                + L"\\nTop:" + std::to_wstring(bounds.top)
                + L"\\nRight:" + std::to_wstring(bounds.right)
                + L"\\nBottom:" + std::to_wstring(bounds.bottom)
                + L"\"}";
          CHECK_FAILURE(sender->PostWebMessageAsJson(reply.c_str()));
       }
       return S_OK;
    }).Get(), &m_webMessageReceivedToken));
    

    窗口边界显示在网页上。

方案:发送 JavaScript 代码

此方案演示如何在 Web 端运行 JavaScript。 在此方法中,主机应用指定要运行的 JavaScript 代码,并通过 将代码传递到 Web ExecuteScriptAsync。 函数 ExecuteScriptAsync 将 JavaScript 结果返回给调用方 ExecuteScript

有关详细信息,请参阅 在 WebView2 中使用 JavaScript (从本机代码) 运行 JavaScript

方案:发送本机对象

将本机对象传递到 Web。 然后从 Web 调用对象的 方法。

若要使用表示方法调用的消息,请使用 AddHostObjectToScript API。 从较高层面上讲,此 API 允许你向 Web 端公开本机 (主机) 对象,并充当代理。 使用 window.chrome.webview.hostObjects.{name}访问这些对象。

接口 ICoreWebView2AddHostObjectToScript 部分介绍了如何将本机对象传递到应用程序的 Web 端。

祝贺你! 你已成功将 Web 内容嵌入本机应用程序。

另请参阅