Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deep-link): add on_open_url Rust API #1780

Merged
merged 3 commits into from
Sep 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions .changes/deep-link-on-new-url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"deep-link": patch
---

Added `DeepLink::on_open_url` function to match the JavaScript API implementation,
which wraps the `deep-link://new-url` event and also send the current deep link if there's any.
16 changes: 7 additions & 9 deletions plugins/deep-link/examples/app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use tauri::Listener;
use tauri_plugin_deep_link::DeepLinkExt;

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

app.deep_link().register_all()?;
}

app.listen("deep-link://new-url", |url| {
dbg!(url);
app.deep_link().on_open_url(|event| {
dbg!(event.urls());
});

Ok(())
})
.invoke_handler(tauri::generate_handler![greet])
Expand Down
68 changes: 62 additions & 6 deletions plugins/deep-link/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::sync::Arc;

use tauri::{
plugin::{Builder, PluginApi, TauriPlugin},
AppHandle, Manager, Runtime,
AppHandle, EventId, Listener, Manager, Runtime,
};

mod commands;
Expand Down Expand Up @@ -57,7 +59,10 @@ fn init_deep_link<R: Runtime>(
},
)?;

return Ok(DeepLink(handle));
return Ok(DeepLink {
app: app.clone(),
plugin_handle: handle,
});
}

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

#[cfg(target_os = "android")]
mod imp {
use tauri::{plugin::PluginHandle, Runtime};
use tauri::{ipc::Channel, plugin::PluginHandle, AppHandle, Runtime};

use serde::{Deserialize, Serialize};
use tauri::ipc::Channel;

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

/// Access to the deep-link APIs.
pub struct DeepLink<R: Runtime>(pub(crate) PluginHandle<R>);
pub struct DeepLink<R: Runtime> {
pub(crate) app: AppHandle<R>,
pub(crate) plugin_handle: PluginHandle<R>,
}

impl<R: Runtime> DeepLink<R> {
/// 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.
Expand All @@ -112,7 +119,7 @@ mod imp {
/// Note that you must manually check the arguments when registering deep link schemes dynamically with [`Self::register`].
/// Additionally, the deep link might have been provided as a CLI argument so you should check if its format matches what you expect.
pub fn get_current(&self) -> crate::Result<Option<Vec<url::Url>>> {
self.0
self.plugin_handle
.run_mobile_plugin::<GetCurrentResponse>("getCurrent", ())
.map(|v| v.url.map(|url| vec![url]))
.map_err(Into::into)
Expand Down Expand Up @@ -437,6 +444,7 @@ mod imp {
}

pub use imp::DeepLink;
use url::Url;

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

/// Event that is triggered when the app was requested to open a new URL.
///
/// Typed [`tauri::Event`].
pub struct OpenUrlEvent {
id: EventId,
urls: Vec<Url>,
}

impl OpenUrlEvent {
/// The event ID which can be used to stop listening to the event via [`tauri::Listener::unlisten`].
pub fn id(&self) -> EventId {
self.id
}

/// The event URLs.
pub fn urls(self) -> Vec<Url> {
self.urls
}
}

impl<R: Runtime> DeepLink<R> {
/// Handle a new deep link being triggered to open the app.
///
/// To avoid race conditions, if the app was started with a deep link,
/// the closure gets immediately called with the deep link URL.
pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId {
let f = Arc::new(f);
let f_ = f.clone();
let event_id = self.app.listen("deep-link://new-url", move |event| {
if let Ok(urls) = serde_json::from_str(event.payload()) {
f(OpenUrlEvent {
id: event.id(),
urls,
})
}
});

if let Ok(Some(current)) = self.get_current() {
f_(OpenUrlEvent {
id: event_id,
urls: current,
})
}

event_id
}
}

/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
Builder::new("deep-link")
Expand Down
Loading