@ -82,32 +82,279 @@ mod imp {
pub struct DeepLink < R : Runtime > ( pub ( crate ) PluginHandle < R > ) ;
impl < R : Runtime > DeepLink < R > {
/// Get the current URLs that triggered the deep link.
/// 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.
///
/// ## Platform-specific:
///
/// - **Windows / Linux**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn get_current ( & self ) -> crate ::Result < Option < Vec < url ::Url > > > {
self . 0
. run_mobile_plugin ::< GetCurrentResponse > ( "getCurrent" , ( ) )
. map ( | v | v . url . map ( | url | vec! [ url ] ) )
. map_err ( Into ::into )
}
/// Register the app as the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`. For example, if you want your app to handle `tauri://` links, call this method with `tauri` as the protocol.
///
/// ## Platform-specific:
///
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn register < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < ( ) > {
Err ( crate ::Error ::UnsupportedPlatform )
}
/// Unregister the app as the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`.
///
/// ## Platform-specific:
///
/// - **Linux**: Can only unregister the scheme if it was initially registered with [`register`](`Self::register`). May not work on older distros.
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn unregister < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < ( ) > {
Err ( crate ::Error ::UnsupportedPlatform )
}
/// Check whether the app is the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`.
///
/// ## Platform-specific:
///
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn is_registered < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < bool > {
Err ( crate ::Error ::UnsupportedPlatform )
}
}
}
#[ cfg(not(target_os = " android " )) ]
mod imp {
use std ::sync ::Mutex ;
#[ cfg(target_os = " linux " ) ]
use std ::{
fs ::{ create_dir_all , File } ,
io ::Write ,
process ::Command ,
} ;
#[ cfg(target_os = " linux " ) ]
use tauri ::Manager ;
use tauri ::{ AppHandle , Runtime } ;
#[ cfg(windows) ]
use windows_registry ::CURRENT_USER ;
/// Access to the deep-link APIs.
pub struct DeepLink < R : Runtime > {
#[ allow(dead_code) ]
pub ( crate ) app : AppHandle < R > ,
#[ allow(dead_code) ]
pub ( crate ) current : Mutex < Option < Vec < url ::Url > > > ,
}
impl < R : Runtime > DeepLink < R > {
/// Get the current URLs that triggered the deep link.
/// 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.
///
/// ## Platform-specific:
///
/// - **Windows / Linux**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn get_current ( & self ) -> crate ::Result < Option < Vec < url ::Url > > > {
Ok ( self . current . lock ( ) . unwrap ( ) . clone ( ) )
#[ cfg(not(any(windows, target_os = " linux " ))) ]
return Ok ( self . current . lock ( ) . unwrap ( ) . clone ( ) ) ;
#[ cfg(any(windows, target_os = " linux " )) ]
Err ( crate ::Error ::UnsupportedPlatform )
}
/// Register the app as the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`. For example, if you want your app to handle `tauri://` links, call this method with `tauri` as the protocol.
///
/// ## Platform-specific:
///
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn register < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < ( ) > {
#[ cfg(windows) ]
{
let key_base = format! ( "Software\\Classes\\{}" , _protocol . as_ref ( ) ) ;
let exe = dunce ::simplified ( & tauri ::utils ::platform ::current_exe ( ) ? )
. display ( )
. to_string ( ) ;
let key_reg = CURRENT_USER . create ( & key_base ) ? ;
key_reg . set_string (
"" ,
& format! ( "URL:{} protocol" , self . app . config ( ) . identifier ) ,
) ? ;
key_reg . set_string ( "URL Protocol" , "" ) ? ;
let icon_reg = CURRENT_USER . create ( format! ( "{key_base}\\DefaultIcon" ) ) ? ;
icon_reg . set_string ( "" , & format! ( "{},0" , & exe ) ) ? ;
let cmd_reg = CURRENT_USER . create ( format! ( "{key_base}\\shell\\open\\command" ) ) ? ;
cmd_reg . set_string ( "" , & format! ( "{} \"%1\"" , & exe ) ) ? ;
Ok ( ( ) )
}
#[ cfg(target_os = " linux " ) ]
{
let bin = tauri ::utils ::platform ::current_exe ( ) ? ;
let file_name = format! (
"{}-handler.desktop" ,
bin . file_name ( ) . unwrap ( ) . to_string_lossy ( )
) ;
let appimage = self . app . env ( ) . appimage ;
let exec = appimage
. clone ( )
. unwrap_or_else ( | | bin . into_os_string ( ) )
. to_string_lossy ( )
. to_string ( ) ;
let target = self . app . path ( ) . data_dir ( ) ? . join ( "applications" ) ;
create_dir_all ( & target ) ? ;
let target_file = target . join ( & file_name ) ;
let mime_type = format! ( "x-scheme-handler/{};" , _protocol . as_ref ( ) ) ;
if let Ok ( mut desktop_file ) = ini ::Ini ::load_from_file ( & target_file ) {
if let Some ( section ) = desktop_file . section_mut ( Some ( "Desktop Entry" ) ) {
if let Some ( mimes ) = section . remove ( "MimeType" ) {
section . append ( "MimeType" , format! ( "{mimes};{mime_type};" ) )
} else {
section . append ( "MimeType" , format! ( "{mime_type};" ) )
}
desktop_file . write_to_file ( & target_file ) ? ;
}
} else {
let mut file = File ::create ( target_file ) ? ;
file . write_all (
format! (
include_str! ( "template.desktop" ) ,
name = self
. app
. config ( )
. product_name
. clone ( )
. unwrap_or_else ( | | file_name . clone ( ) ) ,
exec = exec ,
mime_type = mime_type
)
. as_bytes ( ) ,
) ? ;
}
Command ::new ( "update-desktop-database" )
. arg ( target )
. status ( ) ? ;
Command ::new ( "xdg-mime" )
. args ( [ "default" , & file_name , _protocol . as_ref ( ) ] )
. status ( ) ? ;
Ok ( ( ) )
}
#[ cfg(not(any(windows, target_os = " linux " ))) ]
Err ( crate ::Error ::UnsupportedPlatform )
}
/// Unregister the app as the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`.
///
/// ## Platform-specific:
///
/// - **Linux**: Can only unregister the scheme if it was initially registered with [`register`](`Self::register`). May not work on older distros.
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn unregister < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < ( ) > {
#[ cfg(windows) ]
{
CURRENT_USER . remove_tree ( format! ( "Software\\Classes\\{}" , _protocol . as_ref ( ) ) ) ? ;
Ok ( ( ) )
}
#[ cfg(target_os = " linux " ) ]
{
let mimeapps_path = self . app . path ( ) . config_dir ( ) ? . join ( "mimeapps.list" ) ;
let mut mimeapps = ini ::Ini ::load_from_file ( & mimeapps_path ) ? ;
let file_name = format! (
"{}-handler.desktop" ,
tauri ::utils ::platform ::current_exe ( ) ?
. file_name ( )
. unwrap ( )
. to_string_lossy ( )
) ;
if let Some ( section ) = mimeapps . section_mut ( Some ( "Default Applications" ) ) {
let scheme = format! ( "x-scheme-handler/{}" , _protocol . as_ref ( ) ) ;
if section . get ( & scheme ) . unwrap_or_default ( ) = = file_name {
section . remove ( scheme ) ;
}
}
mimeapps . write_to_file ( mimeapps_path ) ? ;
Ok ( ( ) )
}
#[ cfg(not(any(windows, target_os = " linux " ))) ]
Err ( crate ::Error ::UnsupportedPlatform )
}
/// Check whether the app is the default handler for the specified protocol.
///
/// - `protocol`: The name of the protocol without `://`.
///
/// ## Platform-specific:
///
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn is_registered < S : AsRef < str > > ( & self , _protocol : S ) -> crate ::Result < bool > {
#[ cfg(windows) ]
{
let cmd_reg = CURRENT_USER . open ( format! (
"Software\\Classes\\{}\\shell\\open\\command" ,
_protocol . as_ref ( )
) ) ? ;
let registered_cmd : String = cmd_reg . get_string ( "" ) ? ;
let exe = dunce ::simplified ( & tauri ::utils ::platform ::current_exe ( ) ? )
. display ( )
. to_string ( ) ;
Ok ( registered_cmd = = format! ( "{} \"%1\"" , & exe ) )
}
#[ cfg(target_os = " linux " ) ]
{
let file_name = format! (
"{}-handler.desktop" ,
tauri ::utils ::platform ::current_exe ( ) ?
. file_name ( )
. unwrap ( )
. to_string_lossy ( )
) ;
let output = Command ::new ( "xdg-mime" )
. args ( [
"query" ,
"default" ,
& format! ( "x-scheme-handler/{}" , _protocol . as_ref ( ) ) ,
] )
. output ( ) ? ;
Ok ( String ::from_utf8_lossy ( & output . stdout ) . contains ( & file_name ) )
}
#[ cfg(not(any(windows, target_os = " linux " ))) ]
Err ( crate ::Error ::UnsupportedPlatform )
}
}
}
@ -128,7 +375,12 @@ impl<R: Runtime, T: Manager<R>> crate::DeepLinkExt<R> for T {
/// Initializes the plugin.
pub fn init < R : Runtime > ( ) -> TauriPlugin < R , Option < config ::Config > > {
Builder ::new ( "deep-link" )
. invoke_handler ( tauri ::generate_handler ! [ commands ::get_current ] )
. invoke_handler ( tauri ::generate_handler ! [
commands ::get_current ,
commands ::register ,
commands ::unregister ,
commands ::is_registered
] )
. setup ( | app , api | {
app . manage ( init_deep_link ( app , api ) ? ) ;
Ok ( ( ) )