Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/early-mutex-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

On Android, release REQUEST_HANDLER mutex sooner by cloning the underlying Send + Sync handler.
10 changes: 8 additions & 2 deletions src/android/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,13 @@ fn handle_request(
let webview_id = env.get_string(&webview_id)?;
let webview_id = webview_id.to_str().ok().unwrap_or_default();

if let Some(handler) = REQUEST_HANDLER.lock().unwrap().get(webview_id) {
let handler = REQUEST_HANDLER
.lock()
.unwrap()
.get(webview_id)
.map(|handler| handler.handler.clone());

if let Some(handler) = handler {
Comment thread
Legend-Master marked this conversation as resolved.
#[cfg(feature = "tracing")]
let span =
tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty).entered();
Expand Down Expand Up @@ -162,7 +168,7 @@ fn handle_request(
let response = {
#[cfg(feature = "tracing")]
let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered();
(handler.handler)(
handler(
webview_id,
final_request,
is_document_start_script_enabled != 0,
Expand Down
6 changes: 3 additions & 3 deletions src/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use raw_window_handle::HasWindowHandle;
use std::{
borrow::Cow,
collections::HashMap,
sync::{mpsc::channel, Mutex},
sync::{mpsc::channel, Arc, Mutex},
time::Duration,
};

Expand Down Expand Up @@ -70,7 +70,7 @@ macro_rules! define_static_handlers {

define_static_handlers! {
IPC = UnsafeIpc { handler: Box<dyn Fn(Request<String>)> };
REQUEST_HANDLER = UnsafeRequestHandler { handler: Box<dyn Fn(&str, Request<Vec<u8>>, bool) -> Option<HttpResponse<Cow<'static, [u8]>>>> };
REQUEST_HANDLER = UnsafeRequestHandler { handler: Arc<dyn Fn(&str, Request<Vec<u8>>, bool) -> Option<HttpResponse<Cow<'static, [u8]>>> + Send + Sync> };
TITLE_CHANGE_HANDLER = UnsafeTitleHandler { handler: Box<dyn Fn(String)> };
URL_LOADING_OVERRIDE = UnsafeUrlLoadingOverride { handler: Box<dyn Fn(String) -> bool> };
ON_LOAD_HANDLER = UnsafeOnPageLoadHandler { handler: Box<dyn Fn(PageLoadEvent, String)> };
Expand Down Expand Up @@ -247,7 +247,7 @@ impl InnerWebView {
.unwrap()
.insert(
id.clone(),
UnsafeRequestHandler::new(Box::new(
UnsafeRequestHandler::new(Arc::new(
move |webview_id: &str, mut request, is_document_start_script_enabled| {
let uri = request.uri().to_string();
if let Some((custom_protocol, custom_protocol_handler)) =
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ struct WebViewAttributes<'a> {
/// locate your files in those directories. For more information, see [Loading in-app content](https://developer.android.com/guide/webapps/load-local-content) page.
/// - iOS: To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory.
pub custom_protocols:
Copy link
Copy Markdown
Contributor

@Legend-Master Legend-Master May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucasfernog We do require Send + Sync in tauri, and this change does reflect what we're actually doing, any thoughts?

https://docs.rs/tauri/latest/tauri/struct.Builder.html#method.register_uri_scheme_protocol

Alternatively, we could send the request to main thread and handle things there

HashMap<String, Box<dyn Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder)>>,
HashMap<String, Box<dyn Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + Send + Sync>>,

/// The IPC handler to receive the message from Javascript on webview
/// using `window.ipc.postMessage("insert_message_here")` to host Rust code.
Expand Down Expand Up @@ -1037,7 +1037,7 @@ impl<'a> WebViewBuilder<'a> {
#[cfg(feature = "protocol")]
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
where
F: Fn(WebViewId, Request<Vec<u8>>) -> Response<Cow<'static, [u8]>> + 'static,
F: Fn(WebViewId, Request<Vec<u8>>) -> Response<Cow<'static, [u8]>> + Send + Sync + 'static,
{
#[cfg(any(
target_os = "linux",
Expand Down Expand Up @@ -1102,7 +1102,7 @@ impl<'a> WebViewBuilder<'a> {
#[cfg(feature = "protocol")]
pub fn with_asynchronous_custom_protocol<F>(mut self, name: String, handler: F) -> Self
where
F: Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + 'static,
F: Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + Send + Sync + 'static,
{
#[cfg(any(
target_os = "linux",
Expand Down
3 changes: 2 additions & 1 deletion src/wkwebview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ static COUNTER: Counter = Counter::new();
static WEBVIEW_STATE: Lazy<RwLock<HashMap<String, WebViewState>>> = Lazy::new(Default::default);

struct WebViewState {
pub protocol_ptrs: Vec<Rc<dyn Fn(crate::WebViewId, Request<Vec<u8>>, RequestAsyncResponder)>>,
pub protocol_ptrs:
Vec<Rc<dyn Fn(crate::WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + Send + Sync>>,
}

unsafe impl Send for WebViewState {}
Expand Down
Loading