浏览代码

refactor(core)!: pass webview label to uri scheme protocol handlers (#11163)

* refactor!(core): pass webview label to uri scheme protocol handlers

close #10691

* Add `UriSchemeContext`

* doctests
Amr Bashir 10 月之前
父节点
当前提交
354be36d4e

+ 9 - 0
.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`

+ 28 - 6
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<String>,
     T: Into<Cow<'static, [u8]>>,
-    H: Fn(&AppHandle<R>, http::Request<Vec<u8>>) -> http::Response<T> + Send + Sync + 'static,
+    H: Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>) -> http::Response<T>
+      + 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<String>,
-    H: Fn(&AppHandle<R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync + 'static,
+    H: Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>, 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<R>,
+  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<R> {
+    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<R: Runtime>(menu: &Menu<R>) -> crate::Result<()> {
   menu.inner().init_for_nsapp();

+ 2 - 2
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::{

+ 12 - 9
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<R: Runtime> {
   /// Handler for protocol
   #[allow(clippy::type_complexity)]
   pub protocol:
-    Box<dyn Fn(&AppHandle<R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>,
+    Box<dyn Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>,
 }
 
 pub struct WebviewManager<R: Runtime> {
@@ -210,13 +211,15 @@ impl<R: Runtime> WebviewManager<R> {
     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))
       });
     }
 

+ 11 - 7
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<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   }
 
   /// 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<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   ///
   /// fn init<R: Runtime>() -> TauriPlugin<R> {
   ///   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<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   pub fn register_uri_scheme_protocol<
     N: Into<String>,
     T: Into<Cow<'static, [u8]>>,
-    H: Fn(&AppHandle<R>, http::Request<Vec<u8>>) -> http::Response<T> + Send + Sync + 'static,
+    H: Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>) -> http::Response<T>
+      + Send
+      + Sync
+      + 'static,
   >(
     mut self,
     uri_scheme: N,
@@ -566,8 +570,8 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
     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<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   ///
   /// fn init<R: Runtime>() -> TauriPlugin<R> {
   ///   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<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   #[must_use]
   pub fn register_asynchronous_uri_scheme_protocol<
     N: Into<String>,
-    H: Fn(&AppHandle<R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync + 'static,
+    H: Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync + 'static,
   >(
     mut self,
     uri_scheme: N,

+ 1 - 1
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(