Tauri (6) — Invoke desktop application functionality through the browser
Introduction Most of the online articles focus on Tauri V1. This article primarily discusses the implementation in Tauri V2. In a Tauri V2 application, it's possible to open the app via a specific URL in the browser by configuring the protocol and relevant settings. Let’s walk through the steps to achieve this functionality. Install Plugins Install @tauri-apps/plugin-deep-link This plugin is used to set the Tauri application as the default handler for a specific URL. Method 1: Modify Cargo.toml Add the following to the src-tauri/Cargo.toml file: [dependencies] tauri-plugin-deep-link = "2.0.0" # alternatively with Git: tauri-plugin-deep-link = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } Method 2: Install via JS pnpm add @tauri-apps/plugin-deep-link # or npm add @tauri-apps/plugin-deep-link # or yarn add @tauri-apps/plugin-deep-link # alternatively with Git: pnpm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2 # or npm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2 # or yarn add https://github.com/tauri-apps/tauri-plugin-deep-link#v2 Install tauri-plugin-single-instance This ensures that only a single instance of the Tauri application is running. Configuration: Modify Cargo.toml Add the following to the src-tauri/Cargo.toml file: [dependencies] tauri-plugin-single-instance = "2.0.0" # alternatively with Git: tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } Configure Custom Protocol Tauri supports using custom protocols like tauri:// to open content in the application via the browser. Add the following to the src-tauri/tauri.conf.json file: "plugins": { "features": { "protocol": ["all"] }, "window": {}, "websocket": {}, "shell": {}, "globalShortcut": {}, "deep-link": { "schema": "coco", "mobile": [ { "host": "app.infini.cloud", "pathPrefix": ["/open"] }, { "host": "localhost:9000" } ], "desktop": { "schemes": ["coco"] } } } Implement Custom Protocol Logic Add the following to the src-tauri/src/lib.rs file: use tauri_plugin_deep_link::DeepLinkExt; #[derive(Clone, serde::Serialize)] struct Payload { args: Vec, cwd: String, } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { let mut ctx = tauri::generate_context!(); tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_deep_link::init()) .plugin(tauri_plugin_single_instance::init(|app, argv, cwd| { app.emit("single-instance", Payload { args: argv, cwd }) .unwrap(); })) .invoke_handler(tauri::generate_handler![ ]) .setup(|app| { init(app.app_handle()); #[cfg(target_os = "macos")] app.set_activation_policy(ActivationPolicy::Accessory); #[cfg(any(target_os = "linux", all(debug_assertions, windows)))] app.deep_link().register_all()?; app.deep_link().on_open_url(|event| { dbg!(event.urls()); }); Ok(()) }) .run(ctx) .expect("error while running tauri application"); } Permission Configuration Add the following to the src-tauri/capabilities/default.json file: "permissions": [ "oauth:allow-start", "deep-link:allow-get-current", "deep-link:default", "deep-link:allow-register" ] MacOS Configuration In a Tauri project, src-tauri/Info.plist is a macOS-specific file that defines key properties and behaviors for the application, such as the name, permissions, URL schemes, etc. Modify the src-tauri/Info.plist file: NSCameraUsageDescription Request camera access for WebRTC NSMicrophoneUsageDescription Request microphone access for WebRTC CFBundleIdentifier rs.coco.app NSPrefPaneIconLabel coco-ai CFBundleURLTypes CFBundleURLName rs.coco.app CFBundleURLSchemes coco Frontend Implementation Tauri APP Code: import { onOpenUrl, getCurrent as getCurrentDeepLinkUrls, } from "@tauri-apps/plugin-deep-link"; const handleUrl = (url: string) => { try { const urlObject = new URL(url); console.error("urlObject:", urlObject); switch (urlObject.pathname) { case "oauth_callback": const code = urlObject.searchParams.get("code"); const provider = urlObject.searchParams.get("provider"); // Implement logic here break; default: console.log("Unhandled deep link path:", urlObject.pathname); } } catch (err) { console.error("Failed to parse URL:", err); } }; // Fetch the initial deep link intent useEffect(() => { getCurrentDeepLinkUrls() .then((urls)
Introduction
Most of the online articles focus on Tauri V1. This article primarily discusses the implementation in Tauri V2.
In a Tauri V2 application, it's possible to open the app via a specific URL in the browser by configuring the protocol and relevant settings. Let’s walk through the steps to achieve this functionality.
Install Plugins
Install @tauri-apps/plugin-deep-link
This plugin is used to set the Tauri application as the default handler for a specific URL.
Method 1: Modify Cargo.toml
Add the following to the src-tauri/Cargo.toml
file:
[dependencies]
tauri-plugin-deep-link = "2.0.0"
# alternatively with Git:
tauri-plugin-deep-link = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
Method 2: Install via JS
pnpm add @tauri-apps/plugin-deep-link
# or
npm add @tauri-apps/plugin-deep-link
# or
yarn add @tauri-apps/plugin-deep-link
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
Install tauri-plugin-single-instance
This ensures that only a single instance of the Tauri application is running.
Configuration: Modify Cargo.toml
Add the following to the src-tauri/Cargo.toml
file:
[dependencies]
tauri-plugin-single-instance = "2.0.0"
# alternatively with Git:
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
Configure Custom Protocol
Tauri supports using custom protocols like tauri://
to open content in the application via the browser.
Add the following to the src-tauri/tauri.conf.json
file:
"plugins": {
"features": {
"protocol": ["all"]
},
"window": {},
"websocket": {},
"shell": {},
"globalShortcut": {},
"deep-link": {
"schema": "coco",
"mobile": [
{ "host": "app.infini.cloud", "pathPrefix": ["/open"] },
{ "host": "localhost:9000" }
],
"desktop": {
"schemes": ["coco"]
}
}
}
Implement Custom Protocol Logic
Add the following to the src-tauri/src/lib.rs
file:
use tauri_plugin_deep_link::DeepLinkExt;
#[derive(Clone, serde::Serialize)]
struct Payload {
args: Vec<String>,
cwd: String,
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let mut ctx = tauri::generate_context!();
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
app.emit("single-instance", Payload { args: argv, cwd })
.unwrap();
}))
.invoke_handler(tauri::generate_handler![
])
.setup(|app| {
init(app.app_handle());
#[cfg(target_os = "macos")]
app.set_activation_policy(ActivationPolicy::Accessory);
#[cfg(any(target_os = "linux", all(debug_assertions, windows)))]
app.deep_link().register_all()?;
app.deep_link().on_open_url(|event| {
dbg!(event.urls());
});
Ok(())
})
.run(ctx)
.expect("error while running tauri application");
}
Permission Configuration
Add the following to the src-tauri/capabilities/default.json
file:
"permissions": [
"oauth:allow-start",
"deep-link:allow-get-current",
"deep-link:default",
"deep-link:allow-register"
]
MacOS Configuration
In a Tauri project, src-tauri/Info.plist
is a macOS-specific file that defines key properties and behaviors for the application, such as the name, permissions, URL schemes, etc.
Modify the src-tauri/Info.plist
file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>Request camera access for WebRTC</string>
<key>NSMicrophoneUsageDescription</key>
<string>Request microphone access for WebRTC</string>
<key>CFBundleIdentifier</key>
<string>rs.coco.app</string>
<key>NSPrefPaneIconLabel</key>
<string>coco-ai</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>rs.coco.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>coco</string>
</array>
</dict>
</array>
</dict>
</plist>
Frontend Implementation
Tauri APP Code:
import {
onOpenUrl,
getCurrent as getCurrentDeepLinkUrls,
} from "@tauri-apps/plugin-deep-link";
const handleUrl = (url: string) => {
try {
const urlObject = new URL(url);
console.error("urlObject:", urlObject);
switch (urlObject.pathname) {
case "oauth_callback":
const code = urlObject.searchParams.get("code");
const provider = urlObject.searchParams.get("provider");
// Implement logic here
break;
default:
console.log("Unhandled deep link path:", urlObject.pathname);
}
} catch (err) {
console.error("Failed to parse URL:", err);
}
};
// Fetch the initial deep link intent
useEffect(() => {
getCurrentDeepLinkUrls()
.then((urls) => {
if (urls && urls.length > 0) {
handleUrl(urls[0]);
}
})
.catch((err) => console.error("Failed to get initial URLs:", err));
const unlisten = onOpenUrl((urls) => handleUrl(urls[0]));
return () => {
unlisten.then((fn) => fn());
};
}, []);
Browser Web Code:
<a href="coco://oauth_callback?code=ctvracbq50ke7o4qksj0&provider=coco-cloud">
In order to continue, please click here to launch Coco AI
a>
Use Cases
- Triggering desktop app logic via web pages.
- Integrating OAuth login, payment callbacks, etc., that require browser interaction.
- Cross-platform data exchange.
- Online documentation and help center.
- Dynamic loading and updates.
Summary
With the steps above, we’ve implemented the functionality to open a Tauri app from the browser using a custom protocol, supporting flexible configuration and multi-platform compatibility.
References
Open Source
Recently, I’ve been working on a project based on Tauri called Coco. It’s open source and under continuous improvement. I’d love your support—please give the project a free star
What's Your Reaction?