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 🌟!
This is my first Tauri project, and I’ve been learning while exploring. I look forward to connecting with like-minded individuals to share experiences and grow together!
- Official website: coco.rs/
- Frontend repo: github.com/infinilabs/coco-app
- Backend repo: github.com/infinilabs/coco-server
Thank you for your support and attention!
Top comments (0)