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)

Jan 21, 2025 - 06:27
 0
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<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

  1. Triggering desktop app logic via web pages.
  2. Integrating OAuth login, payment callbacks, etc., that require browser interaction.
  3. Cross-platform data exchange.
  4. Online documentation and help center.
  5. 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

  1. @tauri-apps/plugin-deep-link
  2. tauri-plugin-single-instance
  3. Coco App

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?

like

dislike

love

funny

angry

sad

wow