Skip to content

Commit 62b3a5c

Browse files
fix(core): share webcontext between webviews (#11043)
* fix(core): share webcontext between webviews closes #10981 * update wry version * Update crates/tauri-runtime-wry/src/lib.rs [skip ci] * on linux, only register protocol once per context --------- Co-authored-by: Lucas Fernandes Nogueira <[email protected]> Co-authored-by: Lucas Nogueira <[email protected]>
1 parent 67b8a9a commit 62b3a5c

File tree

2 files changed

+70
-33
lines changed

2 files changed

+70
-33
lines changed

.changes/share-webcontext.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": "patch:bug"
3+
"tauri-runtime-wry": "patch:bug"
4+
---
5+
6+
Fix `localStorage` not shared between webviews that use the same data directory.
7+

crates/tauri-runtime-wry/src/lib.rs

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ use tauri_utils::TitleBarStyle;
6666
use tauri_utils::{config::WindowConfig, Theme};
6767
use url::Url;
6868
use wry::{
69-
DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext, WebView,
70-
WebViewBuilder,
69+
DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext as WryWebContext,
70+
WebView, WebViewBuilder,
7171
};
7272

7373
pub use tao;
@@ -101,7 +101,7 @@ use std::{
101101
cell::RefCell,
102102
collections::{
103103
hash_map::Entry::{Occupied, Vacant},
104-
BTreeMap, HashMap,
104+
BTreeMap, HashMap, HashSet,
105105
},
106106
fmt,
107107
ops::Deref,
@@ -131,6 +131,15 @@ mod undecorated_resizing;
131131
mod webview;
132132
pub use webview::Webview;
133133

134+
#[derive(Debug)]
135+
pub struct WebContext {
136+
pub inner: WryWebContext,
137+
pub referenced_by_webviews: HashSet<String>,
138+
// on Linux the custom protocols are associated with the context
139+
// and you cannot register a URI scheme more than once
140+
pub registered_custom_protocols: HashSet<String>,
141+
}
142+
134143
pub type WebContextStore = Arc<Mutex<HashMap<Option<PathBuf>, WebContext>>>;
135144
// window
136145
pub type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
@@ -216,7 +225,6 @@ pub struct Context<T: UserEvent> {
216225
next_webview_id: Arc<AtomicU32>,
217226
next_window_event_id: Arc<AtomicU32>,
218227
next_webview_event_id: Arc<AtomicU32>,
219-
next_webcontext_id: Arc<AtomicU32>,
220228
}
221229

222230
impl<T: UserEvent> Context<T> {
@@ -246,10 +254,6 @@ impl<T: UserEvent> Context<T> {
246254
fn next_webview_event_id(&self) -> u32 {
247255
self.next_webview_event_id.fetch_add(1, Ordering::Relaxed)
248256
}
249-
250-
fn next_webcontext_id(&self) -> u32 {
251-
self.next_webcontext_id.fetch_add(1, Ordering::Relaxed)
252-
}
253257
}
254258

255259
impl<T: UserEvent> Context<T> {
@@ -2048,7 +2052,15 @@ impl Deref for WebviewWrapper {
20482052
impl Drop for WebviewWrapper {
20492053
fn drop(&mut self) {
20502054
if Rc::get_mut(&mut self.inner).is_some() {
2051-
self.context_store.lock().unwrap().remove(&self.context_key);
2055+
let mut context_store = self.context_store.lock().unwrap();
2056+
2057+
if let Some(web_context) = context_store.get_mut(&self.context_key) {
2058+
web_context.referenced_by_webviews.remove(&self.label);
2059+
2060+
if web_context.referenced_by_webviews.is_empty() {
2061+
context_store.remove(&self.context_key);
2062+
}
2063+
}
20522064
}
20532065
}
20542066
}
@@ -2357,7 +2369,6 @@ impl<T: UserEvent> Wry<T> {
23572369
next_webview_id: Default::default(),
23582370
next_window_event_id: Default::default(),
23592371
next_webview_event_id: Default::default(),
2360-
next_webcontext_id: Default::default(),
23612372
};
23622373

23632374
Ok(Self {
@@ -4104,16 +4115,6 @@ fn create_webview<T: UserEvent>(
41044115
ipc_handler,
41054116
));
41064117

4107-
for (scheme, protocol) in uri_scheme_protocols {
4108-
webview_builder =
4109-
webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
4110-
protocol(
4111-
request,
4112-
Box::new(move |response| responder.respond(response)),
4113-
)
4114-
});
4115-
}
4116-
41174118
for script in webview_attributes.initialization_scripts {
41184119
webview_builder = webview_builder.with_initialization_script(&script);
41194120
}
@@ -4124,30 +4125,59 @@ fn create_webview<T: UserEvent>(
41244125
.lock()
41254126
.expect("poisoned WebContext store");
41264127
let is_first_context = web_context.is_empty();
4128+
// the context must be stored on the HashMap because it must outlive the WebView on macOS
41274129
let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true");
4128-
let web_context_key = // force a unique WebContext when automation is false;
4129-
// the context must be stored on the HashMap because it must outlive the WebView on macOS
4130-
if automation_enabled {
4131-
webview_attributes.data_directory.clone()
4132-
} else {
4133-
// unique key
4134-
let key = context.next_webcontext_id().to_string().into();
4135-
Some(key)
4136-
};
4130+
let web_context_key = webview_attributes.data_directory;
41374131
let entry = web_context.entry(web_context_key.clone());
41384132
let web_context = match entry {
4139-
Occupied(occupied) => occupied.into_mut(),
4133+
Occupied(occupied) => {
4134+
let occupied = occupied.into_mut();
4135+
occupied.referenced_by_webviews.insert(label.clone());
4136+
occupied
4137+
}
41404138
Vacant(vacant) => {
4141-
let mut web_context = WebContext::new(webview_attributes.data_directory);
4139+
let mut web_context = WryWebContext::new(web_context_key.clone());
41424140
web_context.set_allows_automation(if automation_enabled {
41434141
is_first_context
41444142
} else {
41454143
false
41464144
});
4147-
vacant.insert(web_context)
4145+
vacant.insert(WebContext {
4146+
inner: web_context,
4147+
referenced_by_webviews: [label.clone()].into(),
4148+
registered_custom_protocols: HashSet::new(),
4149+
})
41484150
}
41494151
};
41504152

4153+
for (scheme, protocol) in uri_scheme_protocols {
4154+
// on Linux the custom protocols are associated with the web context
4155+
// and you cannot register a scheme more than once
4156+
if cfg!(any(
4157+
target_os = "linux",
4158+
target_os = "dragonfly",
4159+
target_os = "freebsd",
4160+
target_os = "netbsd",
4161+
target_os = "openbsd"
4162+
)) {
4163+
if web_context.registered_custom_protocols.contains(&scheme) {
4164+
continue;
4165+
}
4166+
4167+
web_context
4168+
.registered_custom_protocols
4169+
.insert(scheme.clone());
4170+
}
4171+
4172+
webview_builder =
4173+
webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
4174+
protocol(
4175+
request,
4176+
Box::new(move |response| responder.respond(response)),
4177+
)
4178+
});
4179+
}
4180+
41514181
if webview_attributes.clipboard {
41524182
webview_builder.attrs.clipboard = true;
41534183
}
@@ -4175,7 +4205,7 @@ fn create_webview<T: UserEvent>(
41754205
}
41764206

41774207
let webview = webview_builder
4178-
.with_web_context(web_context)
4208+
.with_web_context(&mut web_context.inner)
41794209
.build()
41804210
.map_err(|e| Error::CreateWebview(Box::new(e)))?;
41814211

0 commit comments

Comments
 (0)