-
-
Notifications
You must be signed in to change notification settings - Fork 455
Expand file tree
/
Copy pathwry_web_view_delegate.rs
More file actions
112 lines (97 loc) · 3.36 KB
/
wry_web_view_delegate.rs
File metadata and controls
112 lines (97 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2020-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::{cell::Cell, ffi::CStr, panic::AssertUnwindSafe};
use http::Request;
use objc2::{
define_class, msg_send,
rc::Retained,
runtime::{NSObject, ProtocolObject},
DeclaredClass, MainThreadOnly,
};
use objc2_foundation::{ns_string, MainThreadMarker, NSObjectProtocol, NSString};
use objc2_web_kit::{WKScriptMessage, WKScriptMessageHandler, WKUserContentController};
pub const IPC_MESSAGE_HANDLER_NAME: &str = "ipc";
pub struct WryWebViewDelegateIvars {
pub controller: Retained<WKUserContentController>,
pub ipc_handler: Box<dyn Fn(Request<String>)>,
pub registered_ipc_handler: Cell<bool>,
}
define_class!(
#[unsafe(super(NSObject))]
#[thread_kind = MainThreadOnly]
#[ivars = WryWebViewDelegateIvars]
pub struct WryWebViewDelegate;
unsafe impl NSObjectProtocol for WryWebViewDelegate {}
unsafe impl WKScriptMessageHandler for WryWebViewDelegate {
// Function for ipc handler
#[unsafe(method(userContentController:didReceiveScriptMessage:))]
fn did_receive(
this: &WryWebViewDelegate,
_controller: &WKUserContentController,
msg: &WKScriptMessage,
) {
// Safety: objc runtime calls are unsafe
unsafe {
#[cfg(feature = "tracing")]
let _span = tracing::info_span!(parent: None, "wry::ipc::handle").entered();
let ipc_handler = &this.ivars().ipc_handler;
let body = msg.body();
if let Ok(body) = body.downcast::<NSString>() {
let js_utf8 = body.UTF8String();
let frame_info = msg.frameInfo();
let request = frame_info.request();
let url = request.URL().unwrap();
let absolute_url = url.absoluteString().unwrap();
let url_utf8 = absolute_url.UTF8String();
if let (Ok(url), Ok(js)) = (
CStr::from_ptr(url_utf8).to_str(),
CStr::from_ptr(js_utf8).to_str(),
) {
if let Ok(r) = Request::builder().uri(url).body(js.to_string()) {
ipc_handler(r);
} else {
#[cfg(feature = "tracing")]
tracing::warn!("WebView received invalid IPC request: {}", js);
}
return;
}
}
#[cfg(feature = "tracing")]
tracing::warn!("WebView received invalid IPC call.");
}
}
}
);
impl WryWebViewDelegate {
pub fn new(
controller: Retained<WKUserContentController>,
ipc_handler: Box<dyn Fn(Request<String>)>,
mtm: MainThreadMarker,
) -> Retained<Self> {
let delegate = mtm
.alloc::<WryWebViewDelegate>()
.set_ivars(WryWebViewDelegateIvars {
ipc_handler,
controller,
registered_ipc_handler: Cell::new(false),
});
let delegate: Retained<Self> = unsafe { msg_send![super(delegate), init] };
let proto_delegate = ProtocolObject::from_ref(&*delegate);
let did_register_ipc_handler = unsafe {
// this will increase the retain count of the delegate
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
}
}