feat(tauri-runtime-wry): ensure webview2 environment options matches

on Windows the Webview2 environment options must match when created webviews sharing the same data directory (unless specified, all webviews share the same data directory). This PR validates the options, warning if they do not match, and forces the webview to be created with the same previous environment to prevent a crash.

discovered as part of #14089
This commit is contained in:
Lucas Nogueira
2025-08-28 13:17:11 -03:00
parent 956b4fd6ff
commit 3f3449d056
2 changed files with 54 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
"tauri-runtime-wry": patch:enhance
---
Validate environment options match previously defined environment for the given data directory on Windows.

View File

@@ -40,7 +40,10 @@ use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
#[cfg(windows)]
use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
#[cfg(windows)]
use webview2_com::{ContainsFullScreenElementChangedEventHandler, FocusChangedEventHandler};
use webview2_com::{
ContainsFullScreenElementChangedEventHandler, FocusChangedEventHandler,
Microsoft::Web::WebView2::Win32::ICoreWebView2Environment,
};
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
#[cfg(target_os = "ios")]
@@ -157,11 +160,24 @@ use window::WindowExt as _;
pub struct WebContext {
pub inner: WryWebContext,
pub referenced_by_webviews: HashSet<String>,
#[cfg(windows)]
environment: Option<ICoreWebView2Environment>,
#[cfg(windows)]
environment_options: WebView2EnvironmentOptions,
// on Linux the custom protocols are associated with the context
// and you cannot register a URI scheme more than once
pub registered_custom_protocols: HashSet<String>,
}
#[cfg(windows)]
#[derive(Debug, PartialEq, Eq)]
struct WebView2EnvironmentOptions {
proxy_url: Option<Url>,
additional_browser_args: Option<String>,
browser_extensions_enabled: bool,
// TODO: scroll_bar_style
}
pub type WebContextStore = Arc<Mutex<HashMap<Option<PathBuf>, WebContext>>>;
// window
pub type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
@@ -4544,6 +4560,13 @@ You may have it installed on another user account, but it is not available for t
..
} = pending;
#[cfg(windows)]
let environment_options = WebView2EnvironmentOptions {
proxy_url: webview_attributes.proxy_url.clone(),
additional_browser_args: webview_attributes.additional_browser_args.clone(),
browser_extensions_enabled: webview_attributes.browser_extensions_enabled,
};
let mut web_context = context
.main_thread
.web_context
@@ -4558,6 +4581,17 @@ You may have it installed on another user account, but it is not available for t
Occupied(occupied) => {
let occupied = occupied.into_mut();
occupied.referenced_by_webviews.insert(label.clone());
#[cfg(windows)]
if cfg!(debug_assertions) && occupied.environment_options != environment_options {
let message =
format!("environment options {environment_options:?} for {web_context_key:?} do not match previously defined options for the same data directory on webviews {:?}, expected {:?}. Since this results in a crash, we are going to force the previously defined environment options", occupied.referenced_by_webviews, occupied.environment_options);
#[cfg(feature = "tracing")]
tracing::warn!("{message}");
#[cfg(not(feature = "tracing"))]
eprintln!("{message}");
}
occupied
}
Vacant(vacant) => {
@@ -4571,6 +4605,10 @@ You may have it installed on another user account, but it is not available for t
inner: web_context,
referenced_by_webviews: [label.clone()].into(),
registered_custom_protocols: HashSet::new(),
#[cfg(windows)]
environment: None,
#[cfg(windows)]
environment_options,
})
}
};
@@ -4584,6 +4622,11 @@ You may have it installed on another user account, but it is not available for t
.with_clipboard(webview_attributes.clipboard)
.with_hotkeys_zoom(webview_attributes.zoom_hotkeys_enabled);
#[cfg(windows)]
if let Some(environment) = &web_context.environment {
webview_builder = webview_builder.with_environment(environment.clone());
}
if url != "about:blank" {
webview_builder = webview_builder.with_url(&url);
}
@@ -5016,6 +5059,11 @@ You may have it installed on another user account, but it is not available for t
#[cfg(windows)]
{
// set the environment on the web context
// important so the next webview with the same context can reuse the environment instance
// to ensure its options matches
web_context.environment.replace(webview.environment());
let controller = webview.controller();
let proxy_clone = context.proxy.clone();
let window_id_ = window_id.clone();