// Copyright 2019-2023 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use serde::de::DeserializeOwned; use tauri::{ plugin::{Builder, PluginApi, TauriPlugin}, AppHandle, Manager, Runtime, }; mod commands; mod config; mod error; pub use error::{Error, Result}; #[cfg(target_os = "android")] const PLUGIN_IDENTIFIER: &str = "app.tauri.deep_link"; fn init_deep_link( app: &AppHandle, _api: PluginApi, ) -> crate::Result> { #[cfg(target_os = "android")] { use tauri::ipc::{Channel, InvokeBody}; let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?; let app_handle = app.clone(); handle.run_mobile_plugin::<()>( "setEventHandler", imp::EventHandler { handler: Channel::new(move |event| { println!("got channel event: {:?}", &event); let url = match event { InvokeBody::Json(payload) => payload .get("url") .and_then(|v| v.as_str()) .map(|s| s.to_owned()), _ => None, }; let _ = app_handle.emit("deep-link://new-url", vec![url]); Ok(()) }), }, )?; return Ok(DeepLink(handle)); } #[cfg(not(target_os = "android"))] Ok(DeepLink { app: app.clone(), current: Default::default(), }) } #[cfg(target_os = "android")] mod imp { use tauri::{plugin::PluginHandle, Runtime}; use serde::{Deserialize, Serialize}; use tauri::ipc::Channel; #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct EventHandler { pub handler: Channel, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct GetCurrentResponse { pub url: Option, } /// Access to the deep-link APIs. pub struct DeepLink(pub(crate) PluginHandle); impl DeepLink { /// Get the current URLs that triggered the deep link. pub fn get_current(&self) -> crate::Result>> { self.0 .run_mobile_plugin::("getCurrent", ()) .map(|v| v.url.map(|url| vec![url])) .map_err(Into::into) } } } #[cfg(not(target_os = "android"))] mod imp { use std::sync::Mutex; use tauri::{AppHandle, Runtime}; /// Access to the deep-link APIs. pub struct DeepLink { #[allow(dead_code)] pub(crate) app: AppHandle, pub(crate) current: Mutex>>, } impl DeepLink { /// Get the current URLs that triggered the deep link. pub fn get_current(&self) -> crate::Result>> { Ok(self.current.lock().unwrap().clone()) } } } pub use imp::DeepLink; /// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the deep-link APIs. pub trait DeepLinkExt { fn deep_link(&self) -> &DeepLink; } impl> crate::DeepLinkExt for T { fn deep_link(&self) -> &DeepLink { self.state::>().inner() } } /// Initializes the plugin. pub fn init() -> TauriPlugin> { Builder::new("deep-link") .js_init_script(include_str!("api-iife.js").to_string()) .invoke_handler(tauri::generate_handler![commands::get_current]) .setup(|app, api| { app.manage(init_deep_link(app, api)?); Ok(()) }) .on_event(|_app, _event| { #[cfg(any(target_os = "macos", target_os = "ios"))] if let tauri::RunEvent::Opened { urls } = _event { let _ = _app.emit("deep-link://new-url", urls); _app.state::>() .current .lock() .unwrap() .replace(urls.clone()); } }) .build() }