diff --git a/.changes/custom-protocol-label.md b/.changes/custom-protocol-label.md new file mode 100644 index 000000000..34b349810 --- /dev/null +++ b/.changes/custom-protocol-label.md @@ -0,0 +1,9 @@ +--- +"tauri": "patch:breaking" +--- + +Changed uri scheme protocol handler to take `UriSchemeContext` as first argument instead of `AppHandle`. `UriSchemeContext` can be used to access an app handle or the webview label that made the request. The following methods are affected: +- `tauri::Builder::register_uri_scheme_protocol` +- `tauri::Builder::register_asynchronous_uri_scheme_protocol` +- `tauri::plugin::Builder::register_uri_scheme_protocol` +- `tauri::plugin::Builder::register_asynchronous_uri_scheme_protocol` diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 4e6b1a844..aaf09897c 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -1665,6 +1665,7 @@ tauri::Builder::default() } /// Registers a URI scheme protocol available to all webviews. + /// /// Leverages [setURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) on macOS, /// [AddWebResourceRequestedFilter](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addwebresourcerequestedfilter?view=webview2-dotnet-1.0.774.44) on Windows /// and [webkit-web-context-register-uri-scheme](https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebContext.html#webkit-web-context-register-uri-scheme) on Linux. @@ -1677,7 +1678,7 @@ tauri::Builder::default() /// # Examples /// ``` /// tauri::Builder::default() - /// .register_uri_scheme_protocol("app-files", |_app, request| { + /// .register_uri_scheme_protocol("app-files", |_ctx, request| { /// // skip leading `/` /// if let Ok(data) = std::fs::read(&request.uri().path()[1..]) { /// http::Response::builder() @@ -1696,7 +1697,10 @@ tauri::Builder::default() pub fn register_uri_scheme_protocol< N: Into, T: Into>, - H: Fn(&AppHandle, http::Request>) -> http::Response + Send + Sync + 'static, + H: Fn(UriSchemeContext<'_, R>, http::Request>) -> http::Response + + Send + + Sync + + 'static, >( mut self, uri_scheme: N, @@ -1705,8 +1709,8 @@ tauri::Builder::default() self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(move |app, request, responder| { - responder.respond(protocol(app, request)) + protocol: Box::new(move |ctx, request, responder| { + responder.respond(protocol(ctx, request)) }), }), ); @@ -1724,7 +1728,7 @@ tauri::Builder::default() /// # Examples /// ``` /// tauri::Builder::default() - /// .register_asynchronous_uri_scheme_protocol("app-files", |_app, request, responder| { + /// .register_asynchronous_uri_scheme_protocol("app-files", |_ctx, request, responder| { /// // skip leading `/` /// let path = request.uri().path()[1..].to_string(); /// std::thread::spawn(move || { @@ -1749,7 +1753,7 @@ tauri::Builder::default() #[must_use] pub fn register_asynchronous_uri_scheme_protocol< N: Into, - H: Fn(&AppHandle, http::Request>, UriSchemeResponder) + Send + Sync + 'static, + H: Fn(UriSchemeContext<'_, R>, http::Request>, UriSchemeResponder) + Send + Sync + 'static, >( mut self, uri_scheme: N, @@ -2001,6 +2005,24 @@ impl UriSchemeResponder { } } +/// Uri scheme protocol context +pub struct UriSchemeContext<'a, R: Runtime> { + pub(crate) app_handle: &'a AppHandle, + pub(crate) webview_label: &'a str, +} + +impl<'a, R: Runtime> UriSchemeContext<'a, R> { + /// Get a reference to an [`AppHandle`]. + pub fn app_handle(&self) -> &'a AppHandle { + self.app_handle + } + + /// Get the webview label that made the uri scheme request. + pub fn webview_label(&self) -> &'a str { + self.webview_label + } +} + #[cfg(target_os = "macos")] fn init_app_menu(menu: &Menu) -> crate::Result<()> { menu.inner().init_for_nsapp(); diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs index a0abfb871..24083cbd3 100644 --- a/crates/tauri/src/lib.rs +++ b/crates/tauri/src/lib.rs @@ -213,8 +213,8 @@ pub use self::utils::TitleBarStyle; pub use self::event::{Event, EventId, EventTarget}; pub use { self::app::{ - App, AppHandle, AssetResolver, Builder, CloseRequestApi, RunEvent, UriSchemeResponder, - WebviewEvent, WindowEvent, + App, AppHandle, AssetResolver, Builder, CloseRequestApi, RunEvent, UriSchemeContext, + UriSchemeResponder, WebviewEvent, WindowEvent, }, self::manager::Asset, self::runtime::{ diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index 0ea38e93d..f625d9294 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -25,7 +25,8 @@ use crate::{ pattern::PatternJavascript, sealed::ManagerBase, webview::PageLoadPayload, - AppHandle, Emitter, EventLoopMessage, EventTarget, Manager, Runtime, Scopes, Webview, Window, + Emitter, EventLoopMessage, EventTarget, Manager, Runtime, Scopes, UriSchemeContext, Webview, + Window, }; use super::{ @@ -61,7 +62,7 @@ pub struct UriSchemeProtocol { /// Handler for protocol #[allow(clippy::type_complexity)] pub protocol: - Box, http::Request>, UriSchemeResponder) + Send + Sync>, + Box, http::Request>, UriSchemeResponder) + Send + Sync>, } pub struct WebviewManager { @@ -210,13 +211,15 @@ impl WebviewManager { for (uri_scheme, protocol) in &*self.uri_scheme_protocols.lock().unwrap() { registered_scheme_protocols.push(uri_scheme.clone()); let protocol = protocol.clone(); - let app_handle = Mutex::new(manager.app_handle().clone()); - pending.register_uri_scheme_protocol(uri_scheme.clone(), move |p, responder| { - (protocol.protocol)( - &app_handle.lock().unwrap(), - p, - UriSchemeResponder(responder), - ) + let app_handle = manager.app_handle().clone(); + let webview_label = label.to_string(); + + pending.register_uri_scheme_protocol(uri_scheme.clone(), move |request, responder| { + let context = UriSchemeContext { + app_handle: &app_handle, + webview_label: webview_label.as_str(), + }; + (protocol.protocol)(context, request, UriSchemeResponder(responder)) }); } diff --git a/crates/tauri/src/plugin.rs b/crates/tauri/src/plugin.rs index 8bdbb721c..cac5be984 100644 --- a/crates/tauri/src/plugin.rs +++ b/crates/tauri/src/plugin.rs @@ -10,7 +10,7 @@ use crate::{ manager::webview::UriSchemeProtocol, utils::config::PluginConfig, webview::PageLoadPayload, - AppHandle, Error, RunEvent, Runtime, Webview, Window, + AppHandle, Error, RunEvent, Runtime, UriSchemeContext, Webview, Window, }; use serde::{ de::{Deserialize, DeserializeOwned, Deserializer, Error as DeError}, @@ -527,6 +527,7 @@ impl Builder { } /// Registers a URI scheme protocol available to all webviews. + /// /// Leverages [setURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) on macOS, /// [AddWebResourceRequestedFilter](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addwebresourcerequestedfilter?view=webview2-dotnet-1.0.774.44) on Windows /// and [webkit-web-context-register-uri-scheme](https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebContext.html#webkit-web-context-register-uri-scheme) on Linux. @@ -547,7 +548,7 @@ impl Builder { /// /// fn init() -> TauriPlugin { /// Builder::new("myplugin") - /// .register_uri_scheme_protocol("myscheme", |app, req| { + /// .register_uri_scheme_protocol("myscheme", |_ctx, req| { /// http::Response::builder().body(Vec::new()).unwrap() /// }) /// .build() @@ -557,7 +558,10 @@ impl Builder { pub fn register_uri_scheme_protocol< N: Into, T: Into>, - H: Fn(&AppHandle, http::Request>) -> http::Response + Send + Sync + 'static, + H: Fn(UriSchemeContext<'_, R>, http::Request>) -> http::Response + + Send + + Sync + + 'static, >( mut self, uri_scheme: N, @@ -566,8 +570,8 @@ impl Builder { self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(move |app, request, responder| { - responder.respond(protocol(app, request)) + protocol: Box::new(move |ctx, request, responder| { + responder.respond(protocol(ctx, request)) }), }), ); @@ -589,7 +593,7 @@ impl Builder { /// /// fn init() -> TauriPlugin { /// Builder::new("myplugin") - /// .register_asynchronous_uri_scheme_protocol("app-files", |_app, request, responder| { + /// .register_asynchronous_uri_scheme_protocol("app-files", |_ctx, request, responder| { /// // skip leading `/` /// let path = request.uri().path()[1..].to_string(); /// std::thread::spawn(move || { @@ -616,7 +620,7 @@ impl Builder { #[must_use] pub fn register_asynchronous_uri_scheme_protocol< N: Into, - H: Fn(&AppHandle, http::Request>, UriSchemeResponder) + Send + Sync + 'static, + H: Fn(UriSchemeContext<'_, R>, http::Request>, UriSchemeResponder) + Send + Sync + 'static, >( mut self, uri_scheme: N, diff --git a/examples/streaming/main.rs b/examples/streaming/main.rs index 5cc8e8cb0..7f8776f83 100644 --- a/examples/streaming/main.rs +++ b/examples/streaming/main.rs @@ -190,7 +190,7 @@ fn main() { download_video(); tauri::Builder::default() - .register_asynchronous_uri_scheme_protocol("stream", move |_app, request, responder| { + .register_asynchronous_uri_scheme_protocol("stream", move |_ctx, request, responder| { match get_stream_response(request) { Ok(http_response) => responder.respond(http_response), Err(e) => responder.respond(