将Libcef打造为win32控件之题外话:试用微软Webview2,尝试加载字符串、拦截资源。

Webview2 之于 windows,等同于 webview 之于安卓系统。Chromium 真是遍地开花啊。目前,Webview2处于公测阶段,用户需安装 edge 的内部版本(insider)才能使用;外界开发者则面临着暂时的文档不够详细、demo无法运行的问题。

官方 demo 仓库:https://github.com/MicrosoftEdge/WebView2Samples

或者(比demo高级点):https://github.com/MicrosoftEdge/WebView2Browser

其中 Webview2Gettingstarted 是最简单的win32示例项目。成功编译运行后,打开一个空窗口,里面一个Webview2控件,导航至www.bing.com。Webview2 功能齐全,右键菜单、页内搜索、下载、常用快捷键(刷新/放大/打印)、dev控制台等等样样具备,关键是产品体积小,运行内存也不大,实在是太振奋人心了!

不过代码不全,需配合官方教程,该复制的复制,头文件该补的补。

源文件仅一个HelloWebview.cpp:https://github.com/MicrosoftEdge/WebView2Samples/blob/master/GettingStartedGuides/Win32_GettingStarted/HelloWebView.cpp

Demo的核心代码如下:

//这个库需要自己创建窗口 hWnd 
    // <-- WebView2 sample code starts here -->

    // Step 3 - Create a single WebView within the parent window
    // Locate the browser and set up the environment for WebView
    auto options = Microsoft::WRL::Make();

    //CreateCoreWebView2EnvironmentWithOptions(TEXT("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\85.0.564.63")
    //  , TEXT("C:\\Users\\TEST\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default")
    //  , options.Get(),
    static wil::com_ptr m_webView;
    static wil::com_ptr m_webViewEnvironment;

    CreateCoreWebView2EnvironmentWithOptions(0,0,0,
        Callback(
            [hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {

        m_webViewEnvironment=env;

        // Create a CoreWebView2Controller and get the associated CoreWebView2 whose parent is the main window hWnd
        env->CreateCoreWebView2Controller(hWnd, Callback(
            [hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
            if (controller != nullptr) {
                webviewController = controller;
                webviewController->get_CoreWebView2(&m_webView);
            }

            // Add a few settings for the webview
            // The demo step is redundant since the values are the default settings
            ICoreWebView2Settings* Settings;
            m_webView->get_Settings(&Settings);
            Settings->put_IsScriptEnabled(TRUE);
            Settings->put_AreDefaultScriptDialogsEnabled(TRUE);
            Settings->put_IsWebMessageEnabled(TRUE);

            // Resize WebView to fit the bounds of the parent window
            RECT bounds;
            GetClientRect(hWnd, &bounds);
            webviewController->put_Bounds(bounds);

            // Schedule an async task to navigate to Bing
            m_webView->Navigate(L"https://www.bing.com/");

            
            // 最简单的demo建立完毕。

            // 以下自行测试各种功能……

            // Step 4 - Navigation events

            // Step 5 - Scripting

            // Step 6 - Communication between host and web content

            return S_OK;
        }).Get());
        return S_OK;
    }).Get());
    
    // <-- WebView2 sample code ends here -->

另有一个示例项目Webview2ApiSample,代码更全,但是无法编译,打开了当参考也好,比看文档强。

成功运行最简Demo后,就可以测试各种功能了:

  • 加载字符串: m_webView->NavigateToString((LPCWSTR)L"哈哈哈哈哈");

管中窥豹,Webview2 的API命名是与众不同的,别人load、load,他偏偏要 Navigate……

  • 添加资源拦截器,拦截所有图片
static EventRegistrationToken m_webResourceRequestedTokenForImageBlocking = {};

//add Filter
m_webView->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE);

//add Handler
CHECK_FAILURE(m_webView->add_WebResourceRequested(
    Callback(
        [hWnd](
            ICoreWebView2* sender,
            ICoreWebView2WebResourceRequestedEventArgs* args) {
    COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext;
    CHECK_FAILURE(
        args->get_ResourceContext(&resourceContext));
    // Ensure that the type is image
    if (resourceContext != COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE)
    {
        return E_INVALIDARG;
    }
    // Override the response with an empty one to block the image.
    // If put_Response is not called, the request will continue as normal.
    wil::com_ptr response;
    //wil::com_ptr> response;

    m_webViewEnvironment->CreateWebResourceResponse(nullptr, 403 /*NoContent*/, L"Blocked", L"", &response);
    CHECK_FAILURE(args->put_Response(response.get()));
    return S_OK;
}).Get(), &m_webResourceRequestedTokenForImageBlocking));

CHECK_FAILURE 来自于 Webview2ApiSample,没什么用,嫌麻烦就拿掉或者#define CHECK_FAILURE。这个lambda表达式是个啥结构暂时看不懂,照样复制粘贴呗!

  • 拦截所有图片,然后替换为本地文件:
wil::com_ptr stream;

CHECK_FAILURE(SHCreateStreamOnFileEx(
    L"D:\\1.jpg", STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr,
    &stream));

m_webViewEnvironment->CreateWebResourceResponse(stream.get(), 200, L"OK", L"", &response);
  • 拦截网址访问,返回中文字符串
if (resourceContext == COREWEBVIEW2_WEB_RESOURCE_CONTEXT_DOCUMENT)
{
    wil::com_ptr req;
    args->get_Request(&req);
    wil::unique_cotaskmem_string navigationTargetUri;
    req->get_Uri(&navigationTargetUri);
    std::wstring uriTarget(navigationTargetUri.get());
    if(uriTarget==L"http://test/MDT/1.html");
    {
        CHAR test_buffer1[1024];
        sprintf(test_buffer1, "%s", " 1234哈哈哈");

        wil::com_ptr response;
        wil::com_ptr stream = SHCreateMemStream((const BYTE*)test_buffer1, strlen(test_buffer1));
        
        CHECK_FAILURE(m_webViewEnvironment->CreateWebResourceResponse(stream.get(), 200, L"OK", L"charset=utf-8", &response));

        wil::com_ptr headers;
        CHECK_FAILURE(response->get_Headers(&headers));
        headers->AppendHeader(L"Content-Type", L"text/html; charset=utf-8");

        CHECK_FAILURE(args->put_Response(response.get()));
        return S_OK;
    }
}

注意在响应头Content-Type中定义正确的MIME类型和编码字符集,否则中文乱码,不能正常显示。

  • JS调用C++
    这个教程第六步有介绍,有点不同,是通过 postMessage 实现的。

  • C++调用JS

m_webView->ExecuteScript(L"window.document.URL;", Callback(
                [](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT {
                LPCWSTR URL = resultObjectAsJson;
                //doSomethingWithURL(URL);
                return S_OK;
            }).Get());

stdfx.h

#include 
#include 
#include 
#include 
#include 
#include 

// include WebView2 header
#include "WebView2.h"
#include "WebView2EnvironmentOptions.h"
// include WebView2 header

using namespace Microsoft::WRL;

编译后的产品有一个 100kb 的依赖: WebView2Loader.dll

还行,很不错!

“将Libcef打造为win32控件”系列:
一:初识Libcef
二:初次封装,拿到浏览器HWND
三:资源拦截替换、JS调用C++ Native、首次运用

你可能感兴趣的:(将Libcef打造为win32控件之题外话:试用微软Webview2,尝试加载字符串、拦截资源。)