diff --git a/.changes/macos-ipc-handlers-undefined.md b/.changes/macos-ipc-handlers-undefined.md new file mode 100644 index 000000000..dbc8c33d7 --- /dev/null +++ b/.changes/macos-ipc-handlers-undefined.md @@ -0,0 +1,9 @@ +--- +"wry": patch +--- + +On macOS, a Tauri v2 app can lose the WebKit message handler used by Tauri IPC after a popup opened via window.open is handled with tauri::webview::NewWindowResponse::Create and then closed. + +After this happens, the opener/main window still has Tauri's JavaScript initialization objects, but later invoke() calls fail because window.webkit.messageHandlers becomes undefined which means it is no longer available. + +Fixed by removing the IPC message handler only if it is registered/owned by the popup. diff --git a/src/wkwebview/class/wry_web_view_delegate.rs b/src/wkwebview/class/wry_web_view_delegate.rs index 58e7d54d3..b98c7427b 100644 --- a/src/wkwebview/class/wry_web_view_delegate.rs +++ b/src/wkwebview/class/wry_web_view_delegate.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{ffi::CStr, panic::AssertUnwindSafe}; +use std::{cell::Cell, ffi::CStr, panic::AssertUnwindSafe}; use http::Request; use objc2::{ @@ -19,6 +19,7 @@ pub const IPC_MESSAGE_HANDLER_NAME: &str = "ipc"; pub struct WryWebViewDelegateIvars { pub controller: Retained, pub ipc_handler: Box)>, + pub registered_ipc_handler: Cell, } define_class!( @@ -85,20 +86,26 @@ impl WryWebViewDelegate { .set_ivars(WryWebViewDelegateIvars { ipc_handler, controller, + registered_ipc_handler: Cell::new(false), }); let delegate: Retained = unsafe { msg_send![super(delegate), init] }; let proto_delegate = ProtocolObject::from_ref(&*delegate); - unsafe { + let did_register_ipc_handler = unsafe { // this will increase the retain count of the delegate - let _res = objc2::exception::catch(AssertUnwindSafe(|| { + objc2::exception::catch(AssertUnwindSafe(|| { delegate .ivars() .controller .addScriptMessageHandler_name(proto_delegate, ns_string!(IPC_MESSAGE_HANDLER_NAME)); - })); - } + })) + .is_ok() + }; + delegate + .ivars() + .registered_ipc_handler + .set(did_register_ipc_handler); delegate } diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 685634980..072c221be 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -1400,12 +1400,14 @@ impl Drop for InnerWebView { // We need to drop handler closures here unsafe { if let Some(ipc_handler) = self.ipc_handler_delegate.take() { - let ipc = ns_string!(IPC_MESSAGE_HANDLER_NAME); - // this will decrease the retain count of the ipc handler and trigger the drop - ipc_handler - .ivars() - .controller - .removeScriptMessageHandlerForName(ipc); + if ipc_handler.ivars().registered_ipc_handler.get() { + let ipc = ns_string!(IPC_MESSAGE_HANDLER_NAME); + // this will decrease the retain count of the ipc handler and trigger the drop + ipc_handler + .ivars() + .controller + .removeScriptMessageHandlerForName(ipc); + } } // Remove webview from window's NSView before dropping.