Skip to content

Commit fdaee9a

Browse files
feat(core/plugin): add register_uri_scheme_protocol, closes #7330 (#7350)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio> closes #7330
1 parent 71a0240 commit fdaee9a

4 files changed

Lines changed: 96 additions & 6 deletions

File tree

.changes/plugin-custom-protocol.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'tauri': 'minor:feat'
3+
---
4+
5+
Add `tauri::plugin::Builder::register_uri_scheme_protocol`

core/tauri/src/app.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,15 @@ impl<R: Runtime> Builder<R> {
14621462
///
14631463
/// * `uri_scheme` The URI scheme to register, such as `example`.
14641464
/// * `protocol` the protocol associated with the given URI scheme. It's a function that takes an URL such as `example://localhost/asset.css`.
1465+
///
1466+
/// # Examples
1467+
///
1468+
/// ```rust
1469+
/// tauri::Builder::default()
1470+
/// .register_uri_scheme_protocol("myscheme", |app, req| {
1471+
/// tauri::http::ResponseBuilder::new().body(Vec::new())
1472+
/// });
1473+
/// ```
14651474
#[must_use]
14661475
pub fn register_uri_scheme_protocol<
14671476
N: Into<String>,

core/tauri/src/manager.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub struct InnerWindowManager<R: Runtime> {
219219

220220
package_info: PackageInfo,
221221
/// The webview protocols available to all windows.
222-
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol<R>>>,
222+
uri_scheme_protocols: Mutex<HashMap<String, Arc<CustomProtocol<R>>>>,
223223
/// The menu set to all windows.
224224
menu: Option<Menu>,
225225
/// Menu event listeners to all windows.
@@ -321,7 +321,7 @@ impl<R: Runtime> WindowManager<R> {
321321
tray_icon: context.system_tray_icon,
322322
package_info: context.package_info,
323323
pattern: context.pattern,
324-
uri_scheme_protocols,
324+
uri_scheme_protocols: Mutex::new(uri_scheme_protocols),
325325
menu,
326326
menu_event_listeners: Arc::new(menu_event_listeners),
327327
window_event_listeners: Arc::new(window_event_listeners),
@@ -350,6 +350,20 @@ impl<R: Runtime> WindowManager<R> {
350350
self.inner.invoke_responder.clone()
351351
}
352352

353+
pub(crate) fn register_uri_scheme_protocol<N: Into<String>>(
354+
&self,
355+
uri_scheme: N,
356+
protocol: Arc<CustomProtocol<R>>,
357+
) {
358+
let uri_scheme = uri_scheme.into();
359+
self
360+
.inner
361+
.uri_scheme_protocols
362+
.lock()
363+
.unwrap()
364+
.insert(uri_scheme, protocol);
365+
}
366+
353367
/// Get the base path to serve data from.
354368
///
355369
/// * In dev mode, this will be based on the `devPath` configuration value.
@@ -461,7 +475,7 @@ impl<R: Runtime> WindowManager<R> {
461475

462476
let mut registered_scheme_protocols = Vec::new();
463477

464-
for (uri_scheme, protocol) in &self.inner.uri_scheme_protocols {
478+
for (uri_scheme, protocol) in &*self.inner.uri_scheme_protocols.lock().unwrap() {
465479
registered_scheme_protocols.push(uri_scheme.clone());
466480
let protocol = protocol.clone();
467481
let app_handle = Mutex::new(app_handle.clone());

core/tauri/src/plugin.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
//! The Tauri plugin extension to expand Tauri functionality.
66
77
use crate::{
8-
utils::config::PluginConfig, AppHandle, Invoke, InvokeHandler, PageLoadPayload, RunEvent,
9-
Runtime, Window,
8+
http::{Request as HttpRequest, Response as HttpResponse},
9+
manager::CustomProtocol,
10+
utils::config::PluginConfig,
11+
AppHandle, Invoke, InvokeHandler, PageLoadPayload, RunEvent, Runtime, Window,
1012
};
1113
use serde::de::DeserializeOwned;
1214
use serde_json::Value as JsonValue;
1315
use tauri_macros::default_runtime;
1416

15-
use std::{collections::HashMap, fmt};
17+
use std::{collections::HashMap, fmt, sync::Arc};
1618

1719
/// The result type of Tauri plugin module.
1820
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
@@ -146,6 +148,7 @@ pub struct Builder<R: Runtime, C: DeserializeOwned = ()> {
146148
on_webview_ready: Box<OnWebviewReady<R>>,
147149
on_event: Box<OnEvent<R>>,
148150
on_drop: Option<Box<OnDrop<R>>>,
151+
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol<R>>>,
149152
}
150153

151154
impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
@@ -161,6 +164,7 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
161164
on_webview_ready: Box::new(|_| ()),
162165
on_event: Box::new(|_, _| ()),
163166
on_drop: None,
167+
uri_scheme_protocols: Default::default(),
164168
}
165169
}
166170

@@ -411,6 +415,57 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
411415
self
412416
}
413417

418+
/// Registers a URI scheme protocol available to all webviews.
419+
/// Leverages [setURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) on macOS,
420+
/// [AddWebResourceRequestedFilter](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addwebresourcerequestedfilter?view=webview2-dotnet-1.0.774.44) on Windows
421+
/// and [webkit-web-context-register-uri-scheme](https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebContext.html#webkit-web-context-register-uri-scheme) on Linux.
422+
///
423+
/// # Known limitations
424+
///
425+
/// URI scheme protocols are registered when the webview is created. Due to this limitation, if the plugin is registed after a webview has been created, this protocol won't be available.
426+
///
427+
/// # Arguments
428+
///
429+
/// * `uri_scheme` The URI scheme to register, such as `example`.
430+
/// * `protocol` the protocol associated with the given URI scheme. It's a function that takes an URL such as `example://localhost/asset.css`.
431+
///
432+
/// # Examples
433+
///
434+
/// ```rust
435+
/// use tauri::{plugin::{Builder, TauriPlugin}, Runtime};
436+
///
437+
/// fn init<R: Runtime>() -> TauriPlugin<R> {
438+
/// Builder::new("myplugin")
439+
/// .register_uri_scheme_protocol("myscheme", |app, req| {
440+
/// tauri::http::ResponseBuilder::new().body(Vec::new())
441+
/// })
442+
/// .build()
443+
/// }
444+
/// ```
445+
#[must_use]
446+
pub fn register_uri_scheme_protocol<
447+
N: Into<String>,
448+
H: Fn(
449+
&AppHandle<R>,
450+
&HttpRequest,
451+
) -> std::result::Result<HttpResponse, Box<dyn std::error::Error>>
452+
+ Send
453+
+ Sync
454+
+ 'static,
455+
>(
456+
mut self,
457+
uri_scheme: N,
458+
protocol: H,
459+
) -> Self {
460+
self.uri_scheme_protocols.insert(
461+
uri_scheme.into(),
462+
Arc::new(CustomProtocol {
463+
protocol: Box::new(protocol),
464+
}),
465+
);
466+
self
467+
}
468+
414469
/// Builds the [TauriPlugin].
415470
pub fn build(self) -> TauriPlugin<R, C> {
416471
TauriPlugin {
@@ -424,6 +479,7 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
424479
on_webview_ready: self.on_webview_ready,
425480
on_event: self.on_event,
426481
on_drop: self.on_drop,
482+
uri_scheme_protocols: self.uri_scheme_protocols,
427483
}
428484
}
429485
}
@@ -440,6 +496,7 @@ pub struct TauriPlugin<R: Runtime, C: DeserializeOwned = ()> {
440496
on_webview_ready: Box<OnWebviewReady<R>>,
441497
on_event: Box<OnEvent<R>>,
442498
on_drop: Option<Box<OnDrop<R>>>,
499+
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol<R>>>,
443500
}
444501

445502
impl<R: Runtime, C: DeserializeOwned> Drop for TauriPlugin<R, C> {
@@ -463,6 +520,11 @@ impl<R: Runtime, C: DeserializeOwned> Plugin<R> for TauriPlugin<R, C> {
463520
if let Some(s) = self.setup_with_config.take() {
464521
(s)(app, serde_json::from_value(config)?)?;
465522
}
523+
for (uri_scheme, protocol) in &self.uri_scheme_protocols {
524+
app
525+
.manager
526+
.register_uri_scheme_protocol(uri_scheme, protocol.clone())
527+
}
466528
Ok(())
467529
}
468530

0 commit comments

Comments
 (0)