WebView2 C++环境配置:从运行时安装到第一个窗口创建

📅 2026/7/31 12:02:39
WebView2 C++环境配置:从运行时安装到第一个窗口创建
1. 项目概述为什么选择WebView2与C的组合如果你正在用C开发Windows桌面应用并且需要在应用里嵌入一个现代化的浏览器内核来展示网页内容、运行Web应用或者构建一个混合架构的界面那么WebView2几乎是当前最主流、也是最推荐的选择。它不是什么新概念本质上就是微软Edge浏览器所使用的Chromium内核但以控件的形式提供给我们开发者调用。相比于老旧的IE控件或者第三方浏览器内核封装WebView2的优势非常明显它直接与系统Edge浏览器共享核心这意味着你的应用能获得与最新版Edge几乎一致的Web平台兼容性和性能支持最新的HTML5、CSS3和JavaScript特性并且随着Edge的更新自动获得安全补丁和功能增强。这个系列教程的第一篇我们就从最基础但也最容易让人“卡住”的环节开始环境初始化。别看只是“初始化”三个字这里面涉及到运行时Runtime的获取、项目的配置、以及第一个窗口的创建每一步都有不少细节。网上很多教程要么过于简略要么默认你已经装好了所有东西导致新手跟着做第一步就报错最常见的就是“Could not find the WebView2 Runtime”或者“Couldn‘t find a compatible WebView2 runtime install”。这篇文章我会结合我多次在全新开发机上配置的经验把每一步的原理、可选方案和避坑点都讲清楚目标是让你看完后能在一个纯净的Windows开发环境上从零成功跑起第一个WebView2的C程序。2. 核心概念与方案选型Fixed Version还是Evergreen在动手写代码之前我们必须先理解WebView2部署的两种核心模式这直接决定了后续的开发和分发策略。很多初学者在这里懵懵懂懂导致后期打包发布时遇到一堆奇怪的问题。2.1 两种运行时分发模式详解WebView2的运行时Runtime可以理解为一个独立的、包含Chromium内核的软件包。你的C程序需要依赖它才能运行。微软提供了两种主要的分发模式Evergreen常青分发模式原理你的应用程序依赖于一个在最终用户机器上“全局安装”的WebView2运行时。这个运行时可以由用户手动安装也可以由你的安装程序静默安装。一旦安装它就像.NET Framework或Visual C Redistributable一样成为系统的一个共享组件。行为当你的应用启动时WebView2控件会去系统指定的位置通常是C:\Program Files (x86)\Microsoft\EdgeWebView2\Application寻找合适版本的运行时。如果找到就加载使用如果没找到或版本不兼容就会触发错误。优点体积小你的应用安装包不需要包含庞大的运行时约180MB安装包小巧。自动更新运行时可以通过Microsoft Edge的更新通道自动更新你的应用能自动获得最新的安全补丁和Web特性支持无需重新发布应用。缺点依赖外部环境你必须确保目标机器上安装了正确版本的运行时。对于离线环境或严格管控的内网环境这可能是个挑战。版本不确定性你无法精确控制用户机器上的运行时版本虽然有大版本兼容性保证但细微差异有时可能引发意想不到的问题尽管很少见。Fixed Version固定版本分发模式原理你将特定版本的WebView2运行时文件一个包含msedgewebview2.exe等文件的文件夹直接打包到你的应用程序目录中。应用程序运行时会优先加载自己目录下的这个固定版本。行为WebView2控件首先在应用本地目录查找运行时如果存在且兼容则使用本地版本完全忽略系统全局安装的版本。优点环境完全可控应用携带了所有依赖对最终用户环境零要求。非常适合离线部署、内网环境或需要绝对版本一致性的场景。简化部署理论上你可以直接复制整个程序文件夹到另一台机器上运行“绿色软件”。缺点应用体积巨大你的安装包需要额外包含约180MB的运行时文件。无法自动更新如果运行时发现安全漏洞你需要主动更新你应用内打包的运行时并重新发布整个应用。2.2 开发阶段与发布阶段的策略选择对于初学者和大多数开发场景我强烈建议采用以下策略开发阶段使用Evergreen模式。这样你的开发机只需要安装一次运行时所有测试项目都能共享节省磁盘空间并能第一时间体验最新的Web特性。本教程的环境配置也将主要围绕Evergreen模式展开。发布阶段根据你的应用受众决定。如果你的应用面向普通互联网用户且可以通过安装程序如MSI、InstallShield进行部署优先考虑Evergreen模式。你的安装程序可以检测并引导用户安装运行时这是最轻量、最可持续的方式。如果你的应用是用于内网、工控、或需要即拷即用的工具则选择Fixed Version模式。虽然体积大但避免了在客户现场配置环境的麻烦。注意很多新手遇到的“Could not find the WebView2 Runtime”错误九成以上是因为在Evergreen模式下开发机或目标机器上没有安装任何WebView2运行时。我们接下来就要解决这个问题。3. 环境准备安装运行时与配置开发环境现在我们开始实际的准备工作。请确保你有一台Windows 10版本1803以上或Windows 11的机器并安装了Visual Studio。3.1 获取并安装WebView2运行时首先我们需要在开发机上安装Evergreen运行时。有几种方法通过安装Microsoft Edge推荐安装或更新Microsoft EdgeChromium版到最新稳定版。Edge的安装包会自动安装与之匹配的Evergreen WebView2运行时。这是最省事的方法。你可以打开Edge在“设置”-“关于Microsoft Edge”中检查更新。独立安装运行时如果你不想安装Edge或者需要特定的运行时版本可以去微软官方下载。打开浏览器搜索“Microsoft Edge WebView2 Runtime 下载”找到微软官方下载页面。选择“Evergreen Standalone Installer”进行下载。这是一个很小的引导安装程序约2MB运行后会在线下载并安装完整的运行时。如何验证安装成功 打开文件资源管理器导航到C:\Program Files (x86)\Microsoft\EdgeWebView2\Application。如果你能看到一个以版本号命名的文件夹例如126.0.2592.81并且里面有msedgewebview2.exe等文件说明运行时已成功安装。实操心得有时候即使安装了Edge这个目录也可能不存在或为空。这可能是因为Edge的安装方式或用户权限问题。一个可靠的检查方法是直接运行我们后面写的测试程序或者使用微软提供的“WebView2 Runtime检测工具”可在上述下载页面找到。如果检测不到尝试以管理员身份重新运行Edge安装程序或独立运行时安装程序。3.2 创建Visual Studio C项目并配置WebView2创建新项目打开Visual Studio我使用的是VS 2022选择“创建新项目”。在模板搜索框中搜索“Windows桌面向导”选择C版本。给项目起个名字比如WebView2Demo选择合适的位置。项目设置在“Windows桌面项目”配置向导中应用程序类型选择“桌面应用程序(.exe)”。附加选项务必勾选“空项目”。我们不需要预生成的Windows桌面代码希望从最干净的状态开始。取消勾选“预编译头”和“安全开发生命周期(SDL)检查”可以简化项目后续可按需添加。添加WebView2 NuGet包关键步骤这是让C项目能使用WebView2 API的核心。在解决方案资源管理器中右键点击你的项目选择“管理NuGet程序包...”。在打开的NuGet包管理器窗口中点击“浏览”选项卡在搜索框中输入Microsoft.Web.WebView2。你应该能看到一个由Microsoft发布的包名称就是Microsoft.Web.WebView2。注意版本对于新手建议选择最新的稳定版非预览版。点击右侧的“安装”按钮。安装过程中Visual Studio会自动下载这个包并将其包含的头文件、库文件以及必要的构建后事件脚本集成到你的项目中。安装成功后你可以在解决方案资源管理器中看到在“引用”下会添加Microsoft.Web.WebView2。在项目目录下会生成一个packages文件夹里面存放着NuGet包的内容。这个NuGet包为我们做了几件重要的事提供了核心头文件WebView2.h和库文件WebView2Loader.dll.lib。自动配置了项目的附加包含目录和附加库目录使得我们可以直接#include WebView2.h。添加了构建后事件确保WebView2Loader.dll被复制到输出目录。4. 编写第一个WebView2窗口从零到一的代码实现环境配置妥当现在我们来编写代码。我们将创建一个最简单的Win32窗口并在其中嵌入一个WebView2控件加载一个百度页面。4.1 项目文件结构与基础Win32窗口首先在项目中添加两个源文件main.cpp和WebView2Manager.h/cpp可选为了结构清晰。我们先从main.cpp开始创建基本的Win32窗口框架。// main.cpp #include windows.h #include WebView2Manager.h // 我们即将创建的管理类 // 全局变量和窗口过程声明 HINSTANCE g_hInstance; const wchar_t WINDOW_CLASS_NAME[] LWebView2DemoWindow; const wchar_t WINDOW_TITLE[] LWebView2 C Demo; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { g_hInstance hInstance; // 1. 注册窗口类 WNDCLASS wc {}; wc.lpfnWndProc WindowProc; wc.hInstance hInstance; wc.lpszClassName WINDOW_CLASS_NAME; wc.hCursor LoadCursor(nullptr, IDC_ARROW); wc.hbrBackground (HBRUSH)(COLOR_WINDOW 1); if (!RegisterClass(wc)) { MessageBox(nullptr, L窗口类注册失败, L错误, MB_ICONERROR); return -1; } // 2. 创建窗口 HWND hwnd CreateWindowEx( 0, WINDOW_CLASS_NAME, WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768, // 初始大小 nullptr, nullptr, hInstance, nullptr ); if (!hwnd) { MessageBox(nullptr, L窗口创建失败, L错误, MB_ICONERROR); return -1; } // 3. 创建并初始化WebView2管理器核心 WebView2Manager* pWebView2Mgr new WebView2Manager(); if (!pWebView2Mgr-Initialize(hwnd)) { MessageBox(hwnd, LWebView2初始化失败请检查运行时是否安装。, L初始化错误, MB_ICONERROR); delete pWebView2Mgr; return -1; } // 将管理器指针存储到窗口的额外数据中方便在窗口过程中获取 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pWebView2Mgr); // 4. 显示窗口并进入消息循环 ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg {}; while (GetMessage(msg, nullptr, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } // 5. 清理 delete pWebView2Mgr; return 0; } // 简单的窗口过程 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WebView2Manager* pMgr (WebView2Manager*)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_SIZE: if (pMgr wParam ! SIZE_MINIMIZED) { // 当窗口大小改变时调整WebView2控件大小 RECT rc; GetClientRect(hwnd, rc); pMgr-ResizeWebView(rc.right - rc.left, rc.bottom - rc.top); } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }4.2 实现WebView2管理器类接下来我们创建WebView2Manager类来封装所有与WebView2交互的复杂逻辑。这是初始化的核心。// WebView2Manager.h #pragma once #include WebView2.h #include WebView2EnvironmentOptions.h #include wrl/client.h // 用于ComPtr智能指针 #include string class WebView2Manager { public: WebView2Manager(); ~WebView2Manager(); bool Initialize(HWND hParentWnd); void ResizeWebView(int width, int height); void Navigate(const std::wstring url); private: // 回调函数声明为静态以便作为C风格函数指针传递 static void CALLBACK OnWebView2EnvironmentCreated(HRESULT result, ICoreWebView2Environment* environment, void* userData); static void CALLBACK OnWebView2ControllerCreated(HRESULT result, ICoreWebView2Controller* controller, void* userData); static void CALLBACK OnNavigationCompleted(ICoreWebView2* webview, ICoreWebView2NavigationCompletedEventArgs* args, void* /*userData*/); // 使用ComPtr智能指针管理COM对象生命周期避免内存泄漏 Microsoft::WRL::ComPtrICoreWebView2Environment m_webviewEnvironment; Microsoft::WRL::ComPtrICoreWebView2Controller m_webviewController; Microsoft::WRL::ComPtrICoreWebView2 m_webview; HWND m_hParentWnd; };// WebView2Manager.cpp #include WebView2Manager.h #include iostream #include wil/com.h // 如果使用WIL库会更方便这里先用标准方法 WebView2Manager::WebView2Manager() : m_hParentWnd(nullptr) {} WebView2Manager::~WebView2Manager() { // ComPtr会自动释放资源 if (m_webviewController) { m_webviewController-Close(); } } bool WebView2Manager::Initialize(HWND hParentWnd) { m_hParentWnd hParentWnd; // 步骤1创建WebView2环境 // CreateCoreWebView2EnvironmentWithOptions是一个异步函数 // 它会在后台查找并初始化运行时完成后调用我们提供的回调函数 OnWebView2EnvironmentCreated HRESULT hr CreateCoreWebView2EnvironmentWithOptions( nullptr, // browserExecutableFolder // 如果为nullptr则使用默认的Evergreen运行时。 // 如果想用Fixed Version这里需指定本地运行时文件夹路径。 nullptr, // userDataFolder // 用于存储缓存、Cookie等数据的目录。nullptr表示使用默认位置。 // 对于多实例应用最好为每个实例指定独立目录。 nullptr, // environmentOptions // 可以传入ICoreWebView2EnvironmentOptions来配置环境如附加命令行参数。 this, // 传递给回调函数的用户数据这里传this指针 OnWebView2EnvironmentCreated // 环境创建完成后的回调函数 ); if (FAILED(hr)) { // 如果立即失败通常是参数错误或内存不足 std::wcerr L创建WebView2环境调用失败HRESULT: hr std::endl; return false; } // 成功调用不代表环境已创建只是异步操作已开始。 // 真正的结果在回调函数 OnWebView2EnvironmentCreated 中处理。 return true; } // 环境创建完成的回调函数 void CALLBACK WebView2Manager::OnWebView2EnvironmentCreated(HRESULT result, ICoreWebView2Environment* environment, void* userData) { WebView2Manager* pThis static_castWebView2Manager*(userData); if (!pThis || !pThis-m_hParentWnd) return; if (FAILED(result) || environment nullptr) { // 环境创建失败这就是最常见的“找不到运行时”错误发生的地方。 // result 可能是 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) 或其他错误码。 MessageBox(pThis-m_hParentWnd, L无法创建WebView2环境。\n请确保已安装Microsoft Edge WebView2运行时。\n(错误码: std::to_wstring(result) L), L环境创建失败, MB_ICONERROR); PostQuitMessage(0); // 退出程序 return; } // 保存环境对象 pThis-m_webviewEnvironment environment; // 步骤2使用创建好的环境来为核心WebView2创建控制器Controller // 控制器负责将WebView2控件与我们的父窗口HWND关联起来 HRESULT hr pThis-m_webviewEnvironment-CreateCoreWebView2Controller( pThis-m_hParentWnd, // 父窗口句柄 pThis, // 用户数据 OnWebView2ControllerCreated // 控制器创建完成后的回调 ); if (FAILED(hr)) { MessageBox(pThis-m_hParentWnd, L创建WebView2控制器失败, L错误, MB_ICONERROR); PostQuitMessage(0); } } // 控制器创建完成的回调函数 void CALLBACK WebView2Manager::OnWebView2ControllerCreated(HRESULT result, ICoreWebView2Controller* controller, void* userData) { WebView2Manager* pThis static_castWebView2Manager*(userData); if (!pThis || FAILED(result) || controller nullptr) { MessageBox(pThis ? pThis-m_hParentWnd : nullptr, LWebView2控制器创建失败, L错误, MB_ICONERROR); if (pThis) PostQuitMessage(0); return; } pThis-m_webviewController controller; // 从控制器获取核心的WebView2对象 HRESULT hr controller-get_CoreWebView2((pThis-m_webview)); if (FAILED(hr) || pThis-m_webview nullptr) { MessageBox(pThis-m_hParentWnd, L获取核心WebView2对象失败, L错误, MB_ICONERROR); PostQuitMessage(0); return; } // 步骤3调整WebView2控件大小使其充满父窗口的客户区 RECT rc; GetClientRect(pThis-m_hParentWnd, rc); pThis-ResizeWebView(rc.right - rc.left, rc.bottom - rc.top); // 步骤4订阅一些有用的事件例如导航完成事件 wil::com_ptrICoreWebView2 webview pThis-m_webview; // 使用WIL简化事件注册需包含wil/com.h // 这里演示传统方法实际更推荐用WIL的callback EventRegistrationToken token; hr pThis-m_webview-add_NavigationCompleted( Microsoft::WRL::CallbackICoreWebView2NavigationCompletedEventHandler( [](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) - HRESULT { BOOL isSuccess; args-get_IsSuccess(isSuccess); if (!isSuccess) { // 导航失败处理 COREWEBVIEW2_WEB_ERROR_STATUS errorStatus; args-get_WebErrorStatus(errorStatus); // 可以记录或提示错误 } else { // 导航成功可以执行一些操作如注入JS OutputDebugStringW(L导航完成\n); } return S_OK; }).Get(), token); // 注意需要保存token在对象销毁前取消订阅这里为简化省略。 // 步骤5导航到一个初始页面 pThis-Navigate(Lhttps://www.baidu.com); } void WebView2Manager::ResizeWebView(int width, int height) { if (m_webviewController) { // 设置WebView2控件边界使其充满整个客户区 RECT bounds {0, 0, width, height}; m_webviewController-put_Bounds(bounds); } } void WebView2Manager::Navigate(const std::wstring url) { if (m_webview) { m_webview-Navigate(url.c_str()); } }4.3 编译与运行确保项目配置正确。在Visual Studio中选择Debug和x64或x86需与运行时架构匹配一般选x64。生成解决方案F7。首次构建可能会稍慢因为要处理NuGet包。运行程序F5。如果一切顺利你将看到一个窗口里面显示着百度首页。5. 常见问题排查与深度调试技巧即使按照步骤操作你也可能会遇到一些问题。这里我整理了最常见的几个坑及其解决方法。5.1 运行时找不到HRESULT: 0x80070002这是头号错误提示信息可能是“Could not find the WebView2 Runtime”。症状程序启动后窗口一闪而过或在OnWebView2EnvironmentCreated回调中收到失败的HRESULT。根本原因系统没有安装任何WebView2 Evergreen运行时或者安装的版本与你的NuGet包引用的API版本不兼容。排查步骤检查目录确认C:\Program Files (x86)\Microsoft\EdgeWebView2\Application是否存在且非空。检查Edge确保安装了基于Chromium的Microsoft Edge并更新到最新版。独立安装从微软官网下载并运行“Evergreen Standalone Installer”。检查架构如果你的应用是x86但系统只安装了x64的运行时或反之也可能失败。确保架构匹配。通常安装Evergreen运行时x86和x64版本都会安装。使用Fixed Version测试在代码中将CreateCoreWebView2EnvironmentWithOptions的第一个参数改为你本地解压的Fixed Version运行时路径需先下载Fixed Version包。如果能成功证明是Evergreen运行时的问题。5.2 编译错误无法打开“WebView2.h”等头文件原因NuGet包没有正确安装或项目配置没有更新。解决清理解决方案并重新生成。在项目属性 - “C/C” - “常规” - “附加包含目录”中检查是否包含了NuGet包提供的路径通常类似$(SolutionDir)packages\Microsoft.Web.WebView2.1.0.xxxx\build\native\include。正常情况下NuGet会自动配置。尝试卸载并重新安装Microsoft.Web.WebView2NuGet包。5.3 链接错误无法解析的外部符号症状类似error LNK2019: 无法解析的外部符号 CreateCoreWebView2EnvironmentWithOptions。原因没有链接WebView2Loader库。解决确保NuGet包已安装。在项目属性 - “链接器” - “输入” - “附加依赖项”中检查是否包含了WebView2Loader.dll.lib。NuGet通常通过属性表自动添加。对于非NuGet的纯手动配置你需要确保WebView2Loader.dll.lib的路径在“附加库目录”中并且WebView2Loader.dll在运行时能被找到通常放在exe同级目录。5.4 程序崩溃或WebView2控件不显示可能原因1窗口句柄无效确保在调用CreateCoreWebView2Controller时传入的HWND是有效的、已创建的窗口句柄。不要在窗口创建完成前例如在WM_CREATE消息处理的最开始就初始化WebView2。可能原因2消息泵Message Pump问题WebView2内部需要处理Windows消息。如果你的程序消息循环不正常比如在控制台程序中滥用可能导致WebView2无法工作。确保有一个标准的GetMessage或PeekMessage循环在运行。可能原因3线程问题WebView2的创建和大部分操作必须在创建它的线程通常是UI线程上进行。不要在其他线程调用其方法。5.5 使用调试输出和日志WebView2的初始化是异步的光靠断点可能不好跟踪。我强烈建议使用OutputDebugString函数来输出日志然后在Visual Studio的“输出”窗口选择“调试”输出查看。// 在关键回调函数开头添加日志 void CALLBACK WebView2Manager::OnWebView2EnvironmentCreated(...) { OutputDebugStringW(L[WebView2] 环境创建回调被调用。\n); if (FAILED(result)) { wchar_t msg[256]; swprintf_s(msg, L[WebView2] 环境创建失败HRESULT: 0x%08X\n, result); OutputDebugStringW(msg); } // ... }这样你可以清晰地看到初始化流程走到了哪一步在哪一步失败。6. 进阶配置与环境选项基础的初始化完成后你可能需要更精细的控制。ICoreWebView2EnvironmentOptions接口提供了这些能力。6.1 指定用户数据文件夹默认情况下WebView2的数据缓存、Cookie、本地存储等会存储在系统默认位置。对于需要独立数据、或便携式应用你可以指定一个自定义文件夹。#include WebView2EnvironmentOptions.h bool WebView2Manager::InitializeWithCustomDataFolder(HWND hParentWnd, const std::wstring dataFolder) { m_hParentWnd hParentWnd; // 创建环境选项 Microsoft::WRL::ComPtrICoreWebView2EnvironmentOptions options; // 注意CreateCoreWebView2EnvironmentOptions是较新版本才有的辅助函数。 // 如果找不到可能需要手动CoCreateInstance。 HRESULT hr CreateCoreWebView2EnvironmentOptions(options.GetAddressOf()); if (SUCCEEDED(hr)) { // 设置数据文件夹路径 options-put_UserDataFolder(dataFolder.c_str()); // 还可以设置其他选项例如 // options-put_AdditionalBrowserArguments(L--disable-featuresSomeFeature); // options-put_Language(Lzh-CN); } // 使用自定义选项创建环境 hr CreateCoreWebView2EnvironmentWithOptions( nullptr, // browserExecutableFolder dataFolder.empty() ? nullptr : dataFolder.c_str(), // userDataFolder (这里也传一次双重保险) options.Get(), // environmentOptions this, OnWebView2EnvironmentCreated ); // ... 后续相同 }注意事项指定的UserDataFolder目录必须存在且应用有读写权限。多个WebView2实例共享同一个数据文件夹可能会导致数据冲突请谨慎设计。6.2 处理新窗口请求弹出窗口默认情况下如果网页中有target_blank的链接WebView2会尝试在默认浏览器中打开。如果你希望在自己的应用内打开新窗口需要处理NewWindowRequested事件。// 在 OnWebView2ControllerCreated 回调中获取WebView2对象后 EventRegistrationToken newWindowToken; hr pThis-m_webview-add_NewWindowRequested( Microsoft::WRL::CallbackICoreWebView2NewWindowRequestedEventHandler( [](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) - HRESULT { // 获取要打开的URI wil::unique_cotaskmem_string uri; args-get_Uri(uri); // 1. 我们可以选择阻止默认行为然后自己导航 // args-put_Handled(TRUE); // sender-Navigate(uri.get()); // 2. 或者获取一个新窗口的“Deferral”异步创建新的WebView2控件来承载 // 这更复杂需要管理多个WebView2实例。 // 这里简单示例阻止并在当前WebView中打开 args-put_Handled(TRUE); sender-Navigate(uri.get()); return S_OK; }).Get(), newWindowToken);环境初始化是使用WebView2的第一步也是最容易出错的一步。理解两种运行时模式、掌握异步创建的回调机制、并学会排查常见的“找不到运行时”错误你就已经成功了一大半。在接下来的教程中我们会深入探讨如何与WebView2中的网页进行双向通信C调用JSJS调用C、处理导航事件、管理Cookie等更高级的主题。