Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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.
Outdated
#[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