From 82efc673e50c7d42f5e06d7130f33c2819f190d9 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:13:51 +0800 Subject: [PATCH 01/24] Add handler for web content process termination on macOS and iOS --- .changes/web-content-process-termination.md | 7 +++++ crates/tauri-runtime-wry/src/lib.rs | 7 +++++ crates/tauri-runtime/src/webview.rs | 8 +++++ crates/tauri/src/webview/mod.rs | 35 +++++++++++++++++++++ crates/tauri/src/webview/webview_window.rs | 16 ++++++++++ 5 files changed, 73 insertions(+) create mode 100644 .changes/web-content-process-termination.md diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md new file mode 100644 index 000000000000..458573482b59 --- /dev/null +++ b/.changes/web-content-process-termination.md @@ -0,0 +1,7 @@ +--- +"tauri": minor:feat +"tauri-runtime": minor:feat +"tauri-runtime-wry": minor:feat +--- + +Add handler for web content process termination on macOS and iOS. diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 1aac9f1aa7e6..87d6d38b612c 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4891,6 +4891,13 @@ You may have it installed on another user account, but it is not available for t webview_builder = webview_builder.with_allow_link_preview(webview_attributes.allow_link_preview); + + if let Some(on_web_content_process_terminate_handler) = + pending.on_web_content_process_terminate_handler + { + webview_builder = webview_builder + .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); + } } #[cfg(target_os = "ios")] diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs index f9c904ef9643..b1446f5b77af 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -41,6 +41,9 @@ type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static; type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync; +#[cfg(any(target_os = "macos", target_os = "ios"))] +type OnWebContentProcessTerminateHandler = dyn Fn() + Send; + #[cfg(target_os = "ios")] type InputAccessoryViewBuilderFn = dyn Fn(&objc2_ui_kit::UIView) -> Option> + Send @@ -224,6 +227,9 @@ pub struct PendingWebview> { pub on_page_load_handler: Option>, pub download_handler: Option>, + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub on_web_content_process_terminate_handler: Option>, } impl> PendingWebview { @@ -250,6 +256,8 @@ impl> PendingWebview { web_resource_request_handler: None, on_page_load_handler: None, download_handler: None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate_handler: None, }) } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index c185e7c62124..201165dd0ff8 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -65,6 +65,8 @@ pub(crate) type UriSchemeProtocolHandler = pub(crate) type OnPageLoad = dyn Fn(Webview, PageLoadPayload<'_>) + Send + Sync + 'static; pub(crate) type OnDocumentTitleChanged = dyn Fn(Webview, String) + Send + 'static; pub(crate) type DownloadHandler = dyn Fn(Webview, DownloadEvent<'_>) -> bool + Send + Sync; +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub(crate) type OnWebContentProcessTerminateHandler = dyn Fn(Webview) + Send; #[derive(Clone, Serialize)] pub(crate) struct CreatedEvent { @@ -278,6 +280,9 @@ unstable_struct!( pub(crate) on_page_load_handler: Option>>, pub(crate) document_title_changed_handler: Option>>, pub(crate) download_handler: Option>>, + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub(crate) on_web_content_process_terminate_handler: + Option>>, } ); @@ -356,6 +361,8 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate_handler: None, } } @@ -435,6 +442,8 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate_handler: None, } } @@ -697,6 +706,17 @@ tauri::Builder::default() self } + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub fn on_web_content_process_terminate) + Send + 'static>( + mut self, + f: F, + ) -> Self { + self + .on_web_content_process_terminate_handler + .replace(Box::new(f)); + self + } + pub(crate) fn into_pending_webview>( mut self, manager: &M, @@ -776,6 +796,21 @@ tauri::Builder::default() } })); + #[cfg(any(target_os = "macos", target_os = "ios"))] + if let Some(on_web_content_process_terminate_handler) = + self.on_web_content_process_terminate_handler.take() + { + let label = pending.label.clone(); + let manager = manager.manager_owned(); + pending + .on_web_content_process_terminate_handler + .replace(Box::new(move || { + if let Some(w) = manager.get_webview(&label) { + on_web_content_process_terminate_handler(w); + } + })); + } + manager .manager() .webview diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index f4a48c168319..084b0fca0f2c 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -441,6 +441,22 @@ tauri::Builder::default() self } + /// Defines a closure to be executed when the web content process terminates. + /// + /// ## Platform-specific + /// + /// - **Linux / Windows / Android:** Unsupported. + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub fn on_web_content_process_terminate) + Send + 'static>( + mut self, + f: F, + ) -> Self { + self.webview_builder = self + .webview_builder + .on_web_content_process_terminate(move |webview| f(webview)); + self + } + /// Creates a new window. pub fn build(self) -> crate::Result> { let (window, webview) = self.window_builder.with_webview(self.webview_builder)?; From f39aeb694167cfb35a206fea9f2936af6430c38a Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 18 Oct 2025 13:49:56 +0800 Subject: [PATCH 02/24] Remove redundant closure --- crates/tauri/src/webview/webview_window.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 084b0fca0f2c..b81abca6f5aa 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -451,9 +451,7 @@ tauri::Builder::default() mut self, f: F, ) -> Self { - self.webview_builder = self - .webview_builder - .on_web_content_process_terminate(move |webview| f(webview)); + self.webview_builder = self.webview_builder.on_web_content_process_terminate(f); self } From 2954c838a005de67c4bb9b7054ae1fadd38dba6a Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 18 Oct 2025 13:53:20 +0800 Subject: [PATCH 03/24] Add documentation --- crates/tauri/src/webview/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 201165dd0ff8..34447fd83e7f 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -706,6 +706,11 @@ tauri::Builder::default() self } + /// Defines a closure to be executed when the web content process terminates. + /// + /// ## Platform-specific + /// + /// - **Linux / Windows / Android:** Unsupported. #[cfg(any(target_os = "macos", target_os = "ios"))] pub fn on_web_content_process_terminate) + Send + 'static>( mut self, From 04c64dcb90f07ba4e3846b59e971abf87c8f854c Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:27:11 +0800 Subject: [PATCH 04/24] Update .changes --- .changes/web-content-process-termination.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md index 458573482b59..adc001afe595 100644 --- a/.changes/web-content-process-termination.md +++ b/.changes/web-content-process-termination.md @@ -1,7 +1,7 @@ --- -"tauri": minor:feat -"tauri-runtime": minor:feat -"tauri-runtime-wry": minor:feat +"tauri": minor:fix +"tauri-runtime": minor:fix +"tauri-runtime-wry": minor:fix --- Add handler for web content process termination on macOS and iOS. From 13bb3808c6293b450a382c97fd079c13854dc671 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:18:25 +0800 Subject: [PATCH 05/24] Update .changes --- .changes/web-content-process-termination.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md index adc001afe595..4b224315e439 100644 --- a/.changes/web-content-process-termination.md +++ b/.changes/web-content-process-termination.md @@ -1,7 +1,7 @@ --- -"tauri": minor:fix -"tauri-runtime": minor:fix -"tauri-runtime-wry": minor:fix +"tauri": "patch:bug" +"tauri-runtime": "patch:bug" +"tauri-runtime-wry": "patch:bug" --- Add handler for web content process termination on macOS and iOS. From fb41639bc21bd8b056197d501aef9dc18d05b266 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:27:29 +0800 Subject: [PATCH 06/24] Add default handler for web content process termination on iOS --- crates/tauri-runtime-wry/src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 22f8f9708d48..cbf88d15f7d6 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4935,6 +4935,26 @@ You may have it installed on another user account, but it is not available for t { webview_builder = webview_builder .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); + } else { + #[cfg(target_os = "ios")] + { + let context_ = context.clone(); + let window_id_ = window_id.clone(); + webview_builder = + webview_builder.with_on_web_content_process_terminate_handler(move || { + let windows = &context_.main_thread.windows.0; + let webview = loop { + if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { + windows + .get(&*window_id_.clone().lock().unwrap()) + .map(|window| window.webviews.first().unwrap().clone()) + }) { + break webview; + }; + }; + webview.reload().unwrap(); + }); + } } } From 9d087bdaad0fa4d70e18480cd10fdeb33e0b7890 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 14 Mar 2026 06:51:56 +0800 Subject: [PATCH 07/24] Use navigate instead of reload when recovering from web content process termination on iOS --- crates/tauri-runtime-wry/src/lib.rs | 20 -------------------- crates/tauri/src/webview/mod.rs | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index cbf88d15f7d6..22f8f9708d48 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4935,26 +4935,6 @@ You may have it installed on another user account, but it is not available for t { webview_builder = webview_builder .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); - } else { - #[cfg(target_os = "ios")] - { - let context_ = context.clone(); - let window_id_ = window_id.clone(); - webview_builder = - webview_builder.with_on_web_content_process_terminate_handler(move || { - let windows = &context_.main_thread.windows.0; - let webview = loop { - if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { - windows - .get(&*window_id_.clone().lock().unwrap()) - .map(|window| window.webviews.first().unwrap().clone()) - }) { - break webview; - }; - }; - webview.reload().unwrap(); - }); - } } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 6c092e322cd3..fa3b3629a457 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -814,6 +814,31 @@ tauri::Builder::default() on_web_content_process_terminate_handler(w); } })); + } else { + #[cfg(target_os = "ios")] + { + let label = pending.label.clone(); + let manager = manager.manager_owned(); + pending + .on_web_content_process_terminate_handler + .replace(Box::new(move || { + if let Some(webview) = manager.get_webview(&label) { + let app_url = manager.get_app_url(pending.webview_attributes.use_https_scheme); + let default_url = app_url.join("/index.html").unwrap(); + let final_url = match webview.url() { + Ok(url) => { + if url.as_str().starts_with(app_url.as_str()) { + url + } else { + default_url + } + } + Err(_) => default_url, + }; + webview.navigate(final_url).unwrap(); + } + })); + } } manager From 4988d6eddaded6ed67dc5eea4476fc229af30304 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:54:34 +0800 Subject: [PATCH 08/24] Fix handler in webview window --- crates/tauri/src/webview/webview_window.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index f613be53fce1..2cb7e8c2c8d9 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -447,11 +447,18 @@ tauri::Builder::default() /// /// - **Linux / Windows / Android:** Unsupported. #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn on_web_content_process_terminate) + Send + 'static>( + pub fn on_web_content_process_terminate) + Send + 'static>( mut self, f: F, ) -> Self { - self.webview_builder = self.webview_builder.on_web_content_process_terminate(f); + self.webview_builder = self.webview_builder.on_web_content_process_terminate(move |webview| { + f( + WebviewWindow { + window: webview.window(), + webview, + }, + ) + }); self } From c5a9f9d53d5c72e352561dbbf2b4837262bae7b7 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:55:07 +0800 Subject: [PATCH 09/24] Reload by default on iOS --- crates/tauri-runtime-wry/src/lib.rs | 20 ++++++++++++++++++++ crates/tauri/src/webview/mod.rs | 25 ------------------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 22f8f9708d48..d5f79151e449 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4935,6 +4935,26 @@ You may have it installed on another user account, but it is not available for t { webview_builder = webview_builder .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); + } else { + #[cfg(target_os = "ios")] + { + let context_ = context.clone(); + let window_id_ = window_id.clone(); + webview_builder = + webview_builder.with_on_web_content_process_terminate_handler(move || { + let windows = &context_.main_thread.windows.0; + let webview = loop { + if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { + windows + .get(&*window_id_.clone().lock().unwrap()) + .map(|window| window.webviews.first().unwrap().clone()) + }) { + break webview; + }; + }; + let _ = webview.reload(); + }); + } } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index fa3b3629a457..6c092e322cd3 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -814,31 +814,6 @@ tauri::Builder::default() on_web_content_process_terminate_handler(w); } })); - } else { - #[cfg(target_os = "ios")] - { - let label = pending.label.clone(); - let manager = manager.manager_owned(); - pending - .on_web_content_process_terminate_handler - .replace(Box::new(move || { - if let Some(webview) = manager.get_webview(&label) { - let app_url = manager.get_app_url(pending.webview_attributes.use_https_scheme); - let default_url = app_url.join("/index.html").unwrap(); - let final_url = match webview.url() { - Ok(url) => { - if url.as_str().starts_with(app_url.as_str()) { - url - } else { - default_url - } - } - Err(_) => default_url, - }; - webview.navigate(final_url).unwrap(); - } - })); - } } manager From 3791c6cd41282fb71a6254426a6697f6d7db70cb Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 18 Mar 2026 08:00:07 +0800 Subject: [PATCH 10/24] Update .changes --- .changes/web-content-process-termination.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md index 4b224315e439..c10fc18cdb69 100644 --- a/.changes/web-content-process-termination.md +++ b/.changes/web-content-process-termination.md @@ -1,7 +1,7 @@ --- -"tauri": "patch:bug" -"tauri-runtime": "patch:bug" -"tauri-runtime-wry": "patch:bug" +"tauri": "minor:feat" +"tauri-runtime": "minor:feat" +"tauri-runtime-wry": "minor:feat" --- Add handler for web content process termination on macOS and iOS. From 1bda59202f86e6231924b9882775160062696aef Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:10:14 +0800 Subject: [PATCH 11/24] Fix code format --- crates/tauri/src/webview/webview_window.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 2cb7e8c2c8d9..532391335458 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -451,14 +451,14 @@ tauri::Builder::default() mut self, f: F, ) -> Self { - self.webview_builder = self.webview_builder.on_web_content_process_terminate(move |webview| { - f( - WebviewWindow { + self.webview_builder = self + .webview_builder + .on_web_content_process_terminate(move |webview| { + f(WebviewWindow { window: webview.window(), webview, - }, - ) - }); + }) + }); self } From 3e7e738bbde064dc756721bf7db83d5847c2d690 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Fri, 20 Mar 2026 07:36:02 +0800 Subject: [PATCH 12/24] Add default handler to macOS --- crates/tauri-runtime-wry/src/lib.rs | 34 +++++++++++++---------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index d5f79151e449..dcc4b3c1e6de 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4936,25 +4936,21 @@ You may have it installed on another user account, but it is not available for t webview_builder = webview_builder .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); } else { - #[cfg(target_os = "ios")] - { - let context_ = context.clone(); - let window_id_ = window_id.clone(); - webview_builder = - webview_builder.with_on_web_content_process_terminate_handler(move || { - let windows = &context_.main_thread.windows.0; - let webview = loop { - if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { - windows - .get(&*window_id_.clone().lock().unwrap()) - .map(|window| window.webviews.first().unwrap().clone()) - }) { - break webview; - }; - }; - let _ = webview.reload(); - }); - } + let context_ = context.clone(); + let window_id_ = window_id.clone(); + webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { + let windows = &context_.main_thread.windows.0; + let webview = loop { + if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { + windows + .get(&*window_id_.clone().lock().unwrap()) + .map(|window| window.webviews.first().unwrap().clone()) + }) { + break webview; + }; + }; + let _ = webview.reload(); + }); } } From f184c59d3e710ecf18f29b7e97c798dc583ec9ed Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 09:55:56 +0800 Subject: [PATCH 13/24] Move function to tauri::Builder --- crates/tauri/src/app.rs | 23 +++++++++++++ crates/tauri/src/manager/mod.rs | 7 +++- crates/tauri/src/manager/webview.rs | 24 ++++++++++++- crates/tauri/src/webview/mod.rs | 40 ---------------------- crates/tauri/src/webview/webview_window.rs | 21 ------------ 5 files changed, 52 insertions(+), 63 deletions(-) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index e8e5343d9abf..0e4c2cc809b3 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -67,6 +67,8 @@ pub type SetupHook = Box) -> std::result::Result<(), Box> + Send>; /// A closure that is run every time a page starts or finishes loading. pub type OnPageLoad = dyn Fn(&Webview, &PageLoadPayload<'_>) + Send + Sync + 'static; +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub type OnWebContentProcessTerminate = dyn Fn(&Webview) + Send + Sync + 'static; pub type ChannelInterceptor = Box, CallbackFn, usize, &InvokeResponseBody) -> bool + Send + Sync + 'static>; @@ -1390,6 +1392,10 @@ pub struct Builder { /// Page load hook. on_page_load: Option>>, + /// Web content process termination hook. + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate: Option>>, + /// All passed plugins plugins: PluginStore, @@ -1476,6 +1482,8 @@ impl Builder { .into_string(), channel_interceptor: None, on_page_load: None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate: None, plugins: PluginStore::default(), uri_scheme_protocols: Default::default(), state: StateManager::new(), @@ -1656,6 +1664,19 @@ tauri::Builder::default() self } + /// Defines the web content process termination hook. + #[cfg(any(target_os = "macos", target_os = "ios"))] + #[must_use] + pub fn on_web_content_process_terminate(mut self, on_web_content_process_terminate: F) -> Self + where + F: Fn(&Webview) + Send + Sync + 'static, + { + self + .on_web_content_process_terminate + .replace(Arc::new(on_web_content_process_terminate)); + self + } + /// Adds a Tauri application plugin. /// /// A plugin is created using the [`crate::plugin::Builder`] struct.Check its documentation for more information. @@ -2104,6 +2125,8 @@ tauri::Builder::default() self.plugins, self.invoke_handler, self.on_page_load, + #[cfg(any(target_os = "macos", target_os = "ios"))] + self.on_web_content_process_terminate, self.uri_scheme_protocols, self.state, #[cfg(desktop)] diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index 25ae8eaabe91..96c8702fb94b 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -21,7 +21,7 @@ use tauri_utils::{ use crate::{ app::{ AppHandle, ChannelInterceptor, GlobalWebviewEventListener, GlobalWindowEventListener, - OnPageLoad, + OnPageLoad, OnWebContentProcessTerminate, }, event::{EmitArgs, Event, EventId, EventTarget, Listeners}, ipc::{Invoke, InvokeHandler, RuntimeAuthority}, @@ -251,6 +251,9 @@ impl AppManager { plugins: PluginStore, invoke_handler: Box>, on_page_load: Option>>, + #[cfg(any(target_os = "macos", target_os = "ios"))] on_web_content_process_terminate: Option< + Arc>, + >, uri_scheme_protocols: HashMap>>, state: StateManager, #[cfg(desktop)] menu_event_listener: Vec>>, @@ -284,6 +287,8 @@ impl AppManager { webviews: Mutex::default(), invoke_handler, on_page_load, + #[cfg(any(target_os = "macos", target_os = "ios"))] + on_web_content_process_terminate, uri_scheme_protocols: Mutex::new(uri_scheme_protocols), event_listeners: Arc::new(webview_event_listeners), invoke_initialization_script, diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index 98c470b76e60..af9072977633 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -20,7 +20,10 @@ use tauri_utils::config::WebviewUrl; use url::Url; use crate::{ - app::{GlobalWebviewEventListener, OnPageLoad, UriSchemeResponder, WebviewEvent}, + app::{ + GlobalWebviewEventListener, OnPageLoad, OnWebContentProcessTerminate, UriSchemeResponder, + WebviewEvent, + }, ipc::InvokeHandler, pattern::PatternJavascript, sealed::ManagerBase, @@ -70,6 +73,9 @@ pub struct WebviewManager { pub invoke_handler: Box>, /// The page load hook, invoked when the webview performs a navigation. pub on_page_load: Option>>, + /// The web content process termination hook. + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub on_web_content_process_terminate: Option>>, /// The webview protocols available to all webviews. pub uri_scheme_protocols: Mutex>>>, /// Webview event listeners to all webviews. @@ -304,6 +310,22 @@ impl WebviewManager { } })); + if pending.on_web_content_process_terminate_handler.is_none() { + let label_ = pending.label.clone(); + let app_manager_ = manager.manager_owned(); + pending + .on_web_content_process_terminate_handler + .replace(Box::new(move || { + if let Some(w) = app_manager_.get_webview(&label_) { + if let Some(on_web_content_process_terminate) = + &app_manager_.webview.on_web_content_process_terminate + { + on_web_content_process_terminate(&w); + } + } + })); + } + #[cfg(feature = "protocol-asset")] if !registered_scheme_protocols.contains(&"asset".into()) { let asset_scope = app_manager diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 6c092e322cd3..8842382bf15a 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -65,8 +65,6 @@ pub(crate) type UriSchemeProtocolHandler = pub(crate) type OnPageLoad = dyn Fn(Webview, PageLoadPayload<'_>) + Send + Sync + 'static; pub(crate) type OnDocumentTitleChanged = dyn Fn(Webview, String) + Send + 'static; pub(crate) type DownloadHandler = dyn Fn(Webview, DownloadEvent<'_>) -> bool + Send + Sync; -#[cfg(any(target_os = "macos", target_os = "ios"))] -pub(crate) type OnWebContentProcessTerminateHandler = dyn Fn(Webview) + Send; #[derive(Clone, Serialize)] pub(crate) struct CreatedEvent { @@ -280,9 +278,6 @@ unstable_struct!( pub(crate) on_page_load_handler: Option>>, pub(crate) document_title_changed_handler: Option>>, pub(crate) download_handler: Option>>, - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub(crate) on_web_content_process_terminate_handler: - Option>>, } ); @@ -361,8 +356,6 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, - #[cfg(any(target_os = "macos", target_os = "ios"))] - on_web_content_process_terminate_handler: None, } } @@ -442,8 +435,6 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, - #[cfg(any(target_os = "macos", target_os = "ios"))] - on_web_content_process_terminate_handler: None, } } @@ -706,22 +697,6 @@ tauri::Builder::default() self } - /// Defines a closure to be executed when the web content process terminates. - /// - /// ## Platform-specific - /// - /// - **Linux / Windows / Android:** Unsupported. - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn on_web_content_process_terminate) + Send + 'static>( - mut self, - f: F, - ) -> Self { - self - .on_web_content_process_terminate_handler - .replace(Box::new(f)); - self - } - pub(crate) fn into_pending_webview>( mut self, manager: &M, @@ -801,21 +776,6 @@ tauri::Builder::default() } })); - #[cfg(any(target_os = "macos", target_os = "ios"))] - if let Some(on_web_content_process_terminate_handler) = - self.on_web_content_process_terminate_handler.take() - { - let label = pending.label.clone(); - let manager = manager.manager_owned(); - pending - .on_web_content_process_terminate_handler - .replace(Box::new(move || { - if let Some(w) = manager.get_webview(&label) { - on_web_content_process_terminate_handler(w); - } - })); - } - manager .manager() .webview diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 532391335458..ca84e83b2426 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -441,27 +441,6 @@ tauri::Builder::default() self } - /// Defines a closure to be executed when the web content process terminates. - /// - /// ## Platform-specific - /// - /// - **Linux / Windows / Android:** Unsupported. - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn on_web_content_process_terminate) + Send + 'static>( - mut self, - f: F, - ) -> Self { - self.webview_builder = self - .webview_builder - .on_web_content_process_terminate(move |webview| { - f(WebviewWindow { - window: webview.window(), - webview, - }) - }); - self - } - /// Creates a new window. pub fn build(self) -> crate::Result> { let (window, webview) = self.window_builder.with_webview(self.webview_builder)?; From 578b7b3222bd27362507e120ae3457dbb297cc3b Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:06:10 +0800 Subject: [PATCH 14/24] Add comment --- crates/tauri/src/app.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 0e4c2cc809b3..8e64355127a8 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -67,6 +67,7 @@ pub type SetupHook = Box) -> std::result::Result<(), Box> + Send>; /// A closure that is run every time a page starts or finishes loading. pub type OnPageLoad = dyn Fn(&Webview, &PageLoadPayload<'_>) + Send + Sync + 'static; +/// A closure that is run when the web content process terminates. #[cfg(any(target_os = "macos", target_os = "ios"))] pub type OnWebContentProcessTerminate = dyn Fn(&Webview) + Send + Sync + 'static; pub type ChannelInterceptor = From 31aef4d0ce23e55ff3ed69e2a820c5394387c81c Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:40:43 +0800 Subject: [PATCH 15/24] Allow fallback handler --- crates/tauri/src/manager/webview.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index af9072977633..71d1a1d42deb 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -311,19 +311,25 @@ impl WebviewManager { })); if pending.on_web_content_process_terminate_handler.is_none() { - let label_ = pending.label.clone(); let app_manager_ = manager.manager_owned(); - pending - .on_web_content_process_terminate_handler - .replace(Box::new(move || { - if let Some(w) = app_manager_.get_webview(&label_) { - if let Some(on_web_content_process_terminate) = - &app_manager_.webview.on_web_content_process_terminate - { - on_web_content_process_terminate(&w); + if app_manager_ + .webview + .on_web_content_process_terminate + .is_some() + { + let label_ = pending.label.clone(); + pending + .on_web_content_process_terminate_handler + .replace(Box::new(move || { + if let Some(w) = app_manager_.get_webview(&label_) { + if let Some(on_web_content_process_terminate) = + &app_manager_.webview.on_web_content_process_terminate + { + on_web_content_process_terminate(&w); + } } - } - })); + })); + } } #[cfg(feature = "protocol-asset")] From 69d4483b0af0bbaa88fd8464fc523f83d54fd769 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:55:55 +0800 Subject: [PATCH 16/24] Add os check --- crates/tauri/src/manager/webview.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index 71d1a1d42deb..919572b031eb 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -310,6 +310,7 @@ impl WebviewManager { } })); + #[cfg(any(target_os = "macos", target_os = "ios"))] if pending.on_web_content_process_terminate_handler.is_none() { let app_manager_ = manager.manager_owned(); if app_manager_ From f28ede54b94184758d79ee5cb809a4f9384d61dd Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:04:07 +0800 Subject: [PATCH 17/24] Add os checks to use declarations --- crates/tauri/src/manager/mod.rs | 5 ++++- crates/tauri/src/manager/webview.rs | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index 96c8702fb94b..58b6d994ed10 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -21,7 +21,7 @@ use tauri_utils::{ use crate::{ app::{ AppHandle, ChannelInterceptor, GlobalWebviewEventListener, GlobalWindowEventListener, - OnPageLoad, OnWebContentProcessTerminate, + OnPageLoad, }, event::{EmitArgs, Event, EventId, EventTarget, Listeners}, ipc::{Invoke, InvokeHandler, RuntimeAuthority}, @@ -31,6 +31,9 @@ use crate::{ Assets, Context, DebugAppIcon, EventName, Pattern, Runtime, StateManager, Webview, Window, }; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use crate::app::OnWebContentProcessTerminate; + #[cfg(desktop)] mod menu; #[cfg(all(desktop, feature = "tray-icon"))] diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index 919572b031eb..ee15597e39f5 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -20,10 +20,7 @@ use tauri_utils::config::WebviewUrl; use url::Url; use crate::{ - app::{ - GlobalWebviewEventListener, OnPageLoad, OnWebContentProcessTerminate, UriSchemeResponder, - WebviewEvent, - }, + app::{GlobalWebviewEventListener, OnPageLoad, UriSchemeResponder, WebviewEvent}, ipc::InvokeHandler, pattern::PatternJavascript, sealed::ManagerBase, @@ -31,6 +28,9 @@ use crate::{ EventLoopMessage, EventTarget, Manager, Runtime, Scopes, UriSchemeContext, Webview, Window, }; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use crate::app::OnWebContentProcessTerminate; + use super::{ window::{DragDropPayload, DRAG_DROP_EVENT, DRAG_ENTER_EVENT, DRAG_LEAVE_EVENT, DRAG_OVER_EVENT}, {AppManager, EmitPayload}, From cfa6a38c03140300e23be3a7b776e2bbe71892b9 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:18:21 +0800 Subject: [PATCH 18/24] Fix tests --- crates/tauri/src/ipc/protocol.rs | 4 ++++ crates/tauri/src/manager/mod.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/crates/tauri/src/ipc/protocol.rs b/crates/tauri/src/ipc/protocol.rs index 1b1e08b8f9b4..72dea2821b07 100644 --- a/crates/tauri/src/ipc/protocol.rs +++ b/crates/tauri/src/ipc/protocol.rs @@ -571,6 +571,8 @@ mod tests { PluginStore::default(), Box::new(|_| false), None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + None, Default::default(), StateManager::new(), Default::default(), @@ -687,6 +689,8 @@ mod tests { PluginStore::default(), Box::new(|_| false), None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + None, Default::default(), StateManager::new(), Default::default(), diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index 58b6d994ed10..7b1f224137a8 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -770,6 +770,8 @@ mod test { PluginStore::default(), Box::new(|_| false), None, + #[cfg(any(target_os = "macos", target_os = "ios"))] + None, Default::default(), StateManager::new(), Default::default(), From e491659cfcb80168b1816367646009dcf3225475 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:33:18 +0800 Subject: [PATCH 19/24] Update comment with platform support Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com> --- crates/tauri/src/app.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 8e64355127a8..30927e12ba53 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -1666,6 +1666,10 @@ tauri::Builder::default() } /// Defines the web content process termination hook. + /// + /// ## Platform-specific + /// + /// - **Linux / Windows / Android:** Unsupported. #[cfg(any(target_os = "macos", target_os = "ios"))] #[must_use] pub fn on_web_content_process_terminate(mut self, on_web_content_process_terminate: F) -> Self From 129f0fbaf8ace3f3853a8d13b44d6b01b92f9d58 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:29:14 +0800 Subject: [PATCH 20/24] Simplify default handler logic --- crates/tauri-runtime-wry/src/lib.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index dcc4b3c1e6de..937aa5a48168 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4939,17 +4939,13 @@ You may have it installed on another user account, but it is not available for t let context_ = context.clone(); let window_id_ = window_id.clone(); webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { - let windows = &context_.main_thread.windows.0; - let webview = loop { - if let Some(webview) = windows.try_borrow().ok().and_then(|windows| { - windows - .get(&*window_id_.clone().lock().unwrap()) - .map(|window| window.webviews.first().unwrap().clone()) - }) { - break webview; - }; - }; - let _ = webview.reload(); + if let Ok(windows) = &context_.main_thread.windows.0.try_borrow() { + if let Some(window) = windows.get(&*window_id_.clone().lock().unwrap()) { + for webview in &window.webviews { + let _ = webview.reload(); + } + } + } }); } } From 23250c0133ed385aa8f50fd4072f9794c75c26c8 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:40:33 +0800 Subject: [PATCH 21/24] Fix default handler --- crates/tauri-runtime-wry/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 937aa5a48168..181d547797b4 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4941,7 +4941,7 @@ You may have it installed on another user account, but it is not available for t webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { if let Ok(windows) = &context_.main_thread.windows.0.try_borrow() { if let Some(window) = windows.get(&*window_id_.clone().lock().unwrap()) { - for webview in &window.webviews { + if let Some(webview) = window.webviews.iter().find(|w| w.id == id) { let _ = webview.reload(); } } From b6fb7ec299e45a8173798f87a524bbbee63ae9b7 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 4 Apr 2026 06:57:19 +0800 Subject: [PATCH 22/24] Remove extra clone --- crates/tauri-runtime-wry/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 181d547797b4..b1f7d8108715 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4940,7 +4940,7 @@ You may have it installed on another user account, but it is not available for t let window_id_ = window_id.clone(); webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { if let Ok(windows) = &context_.main_thread.windows.0.try_borrow() { - if let Some(window) = windows.get(&*window_id_.clone().lock().unwrap()) { + if let Some(window) = windows.get(*window_id_.lock().unwrap()) { if let Some(webview) = window.webviews.iter().find(|w| w.id == id) { let _ = webview.reload(); } From 7160b468df8beef3387f8683ac86efd2ae20d967 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 4 Apr 2026 07:01:17 +0800 Subject: [PATCH 23/24] Fix default handler --- crates/tauri-runtime-wry/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index b1f7d8108715..93f8aa81cc17 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4940,7 +4940,7 @@ You may have it installed on another user account, but it is not available for t let window_id_ = window_id.clone(); webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { if let Ok(windows) = &context_.main_thread.windows.0.try_borrow() { - if let Some(window) = windows.get(*window_id_.lock().unwrap()) { + if let Some(window) = windows.get(&*window_id_.lock().unwrap()) { if let Some(webview) = window.webviews.iter().find(|w| w.id == id) { let _ = webview.reload(); } From e8991c20ea10861de2a0d7b660df67b1a7730bc0 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Sat, 4 Apr 2026 08:29:04 +0800 Subject: [PATCH 24/24] Add logging --- crates/tauri-runtime-wry/src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 93f8aa81cc17..5e8b1f8f7c72 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4936,15 +4936,25 @@ You may have it installed on another user account, but it is not available for t webview_builder = webview_builder .with_on_web_content_process_terminate_handler(on_web_content_process_terminate_handler); } else { + log::debug!("web content process terminated"); let context_ = context.clone(); let window_id_ = window_id.clone(); webview_builder = webview_builder.with_on_web_content_process_terminate_handler(move || { if let Ok(windows) = &context_.main_thread.windows.0.try_borrow() { if let Some(window) = windows.get(&*window_id_.lock().unwrap()) { if let Some(webview) = window.webviews.iter().find(|w| w.id == id) { - let _ = webview.reload(); + match webview.reload() { + Ok(_) => log::debug!("webview reloaded"), + Err(e) => log::error!("failed to reload webview: {}", e), + } + } else { + log::error!("failed to find webview") } + } else { + log::error!("failed to get window") } + } else { + log::error!("failed to borrow windows") } }); }