Skip to content

Commit 6f3f667

Browse files
authored
feat(deep-link): add on_open_url Rust API (#1780)
1 parent 79d6e19 commit 6f3f667

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

.changes/deep-link-on-new-url.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"deep-link": patch
3+
---
4+
5+
Added `DeepLink::on_open_url` function to match the JavaScript API implementation,
6+
which wraps the `deep-link://new-url` event and also send the current deep link if there's any.

plugins/deep-link/examples/app/src-tauri/src/lib.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5-
use tauri::Listener;
5+
use tauri_plugin_deep_link::DeepLinkExt;
66

77
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
88
#[tauri::command]
@@ -33,16 +33,14 @@ pub fn run() {
3333
// ensure deep links are registered on the system
3434
// this is useful because AppImages requires additional setup to be available in the system
3535
// and calling register() makes the deep links immediately available - without any user input
36-
#[cfg(target_os = "linux")]
37-
{
38-
use tauri_plugin_deep_link::DeepLinkExt;
36+
// additionally, we manually register on Windows on debug builds for development
37+
#[cfg(any(target_os = "linux", all(debug_assertions, windows)))]
38+
app.deep_link().register_all()?;
3939

40-
app.deep_link().register_all()?;
41-
}
42-
43-
app.listen("deep-link://new-url", |url| {
44-
dbg!(url);
40+
app.deep_link().on_open_url(|event| {
41+
dbg!(event.urls());
4542
});
43+
4644
Ok(())
4745
})
4846
.invoke_handler(tauri::generate_handler![greet])

plugins/deep-link/src/lib.rs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5+
use std::sync::Arc;
6+
57
use tauri::{
68
plugin::{Builder, PluginApi, TauriPlugin},
7-
AppHandle, Manager, Runtime,
9+
AppHandle, EventId, Listener, Manager, Runtime,
810
};
911

1012
mod commands;
@@ -57,7 +59,10 @@ fn init_deep_link<R: Runtime>(
5759
},
5860
)?;
5961

60-
return Ok(DeepLink(handle));
62+
return Ok(DeepLink {
63+
app: app.clone(),
64+
plugin_handle: handle,
65+
});
6166
}
6267

6368
#[cfg(target_os = "ios")]
@@ -83,10 +88,9 @@ fn init_deep_link<R: Runtime>(
8388

8489
#[cfg(target_os = "android")]
8590
mod imp {
86-
use tauri::{plugin::PluginHandle, Runtime};
91+
use tauri::{ipc::Channel, plugin::PluginHandle, AppHandle, Runtime};
8792

8893
use serde::{Deserialize, Serialize};
89-
use tauri::ipc::Channel;
9094

9195
#[derive(Serialize)]
9296
#[serde(rename_all = "camelCase")]
@@ -101,7 +105,10 @@ mod imp {
101105
}
102106

103107
/// Access to the deep-link APIs.
104-
pub struct DeepLink<R: Runtime>(pub(crate) PluginHandle<R>);
108+
pub struct DeepLink<R: Runtime> {
109+
pub(crate) app: AppHandle<R>,
110+
pub(crate) plugin_handle: PluginHandle<R>,
111+
}
105112

106113
impl<R: Runtime> DeepLink<R> {
107114
/// Get the current URLs that triggered the deep link. Use this on app load to check whether your app was started via a deep link.
@@ -112,7 +119,7 @@ mod imp {
112119
/// Note that you must manually check the arguments when registering deep link schemes dynamically with [`Self::register`].
113120
/// Additionally, the deep link might have been provided as a CLI argument so you should check if its format matches what you expect.
114121
pub fn get_current(&self) -> crate::Result<Option<Vec<url::Url>>> {
115-
self.0
122+
self.plugin_handle
116123
.run_mobile_plugin::<GetCurrentResponse>("getCurrent", ())
117124
.map(|v| v.url.map(|url| vec![url]))
118125
.map_err(Into::into)
@@ -437,6 +444,7 @@ mod imp {
437444
}
438445

439446
pub use imp::DeepLink;
447+
use url::Url;
440448

441449
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the deep-link APIs.
442450
pub trait DeepLinkExt<R: Runtime> {
@@ -449,6 +457,54 @@ impl<R: Runtime, T: Manager<R>> crate::DeepLinkExt<R> for T {
449457
}
450458
}
451459

460+
/// Event that is triggered when the app was requested to open a new URL.
461+
///
462+
/// Typed [`tauri::Event`].
463+
pub struct OpenUrlEvent {
464+
id: EventId,
465+
urls: Vec<Url>,
466+
}
467+
468+
impl OpenUrlEvent {
469+
/// The event ID which can be used to stop listening to the event via [`tauri::Listener::unlisten`].
470+
pub fn id(&self) -> EventId {
471+
self.id
472+
}
473+
474+
/// The event URLs.
475+
pub fn urls(self) -> Vec<Url> {
476+
self.urls
477+
}
478+
}
479+
480+
impl<R: Runtime> DeepLink<R> {
481+
/// Handle a new deep link being triggered to open the app.
482+
///
483+
/// To avoid race conditions, if the app was started with a deep link,
484+
/// the closure gets immediately called with the deep link URL.
485+
pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId {
486+
let f = Arc::new(f);
487+
let f_ = f.clone();
488+
let event_id = self.app.listen("deep-link://new-url", move |event| {
489+
if let Ok(urls) = serde_json::from_str(event.payload()) {
490+
f(OpenUrlEvent {
491+
id: event.id(),
492+
urls,
493+
})
494+
}
495+
});
496+
497+
if let Ok(Some(current)) = self.get_current() {
498+
f_(OpenUrlEvent {
499+
id: event_id,
500+
urls: current,
501+
})
502+
}
503+
504+
event_id
505+
}
506+
}
507+
452508
/// Initializes the plugin.
453509
pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
454510
Builder::new("deep-link")

0 commit comments

Comments
 (0)