Rust跨平台应用Tauri插件tauri-plugin-deep-link的使用,实现深度链接处理与自定义URL协议支持

plugin-deep-link

将您的Tauri应用程序设置为URL的默认处理程序。

平台 支持
Linux
Windows
macOS
Android
iOS

安装

此插件需要至少Rust版本1.77.2

我们推荐三种通用的安装方法。

  1. 使用crates.io和npm(最简单,需要您信任我们的发布管道正常工作)
  2. 使用git标签/修订哈希直接从Github拉取源代码(最安全)
  3. 在您的Tauri项目中使用git子模块安装此仓库,然后使用文件协议引入源代码(最安全,但使用不便)

通过将以下内容添加到您的Cargo.toml文件来安装核心插件:

src-tauri/Cargo.toml

[dependencies]
tauri-plugin-deep-link = "2.0.0"
# 或者使用Git:
tauri-plugin-deep-link = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }

您可以使用您喜欢的JavaScript包管理器安装JavaScript Guest绑定:

pnpm add @tauri-apps/plugin-deep-link
# 或者
npm add @tauri-apps/plugin-deep-link
# 或者
yarn add @tauri-apps/plugin-deep-link

设置

Android

对于应用链接,您需要一个具有.well-known/assetlinks.json端点的服务器,该端点必须以给定格式返回文本响应:

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "$APP_BUNDLE_ID",
      "sha256_cert_fingerprints": [
        $CERT_FINGERPRINT
      ]
    }
  }
]

其中$APP_BUNDLE_ID是在tauri.conf.json > identifier中定义的值,将-替换为_$CERT_FINGERPRINT是您的应用签名证书的SHA256指纹列表。

iOS

对于通用链接,您需要一个具有.well-known/apple-app-site-association端点的服务器,该端点必须以给定格式返回文本响应:

{
  "applinks": {
    "details": [
      {
        "appIDs": [ "$DEVELOPMENT_TEAM_ID.$APP_BUNDLE_ID" ],
        "components": [
          {
            "/": "/open/*",
            "comment": "匹配任何路径以/open/开头的URL"
          }
        ]
      }
    ]
  }
}

其中$DEVELOPMENT_TEAM_ID是在tauri.conf.json > bundle > iOS > developmentTeam中定义的值或APPLE_DEVELOPMENT_TEAM环境变量,$APP_BUNDLE_ID是在tauri.conf.json > identifier中定义的值。

要验证您的域是否已正确配置以公开应用关联,您可以运行以下命令:

curl -v https://app-site-association.cdn-apple.com/a/v1/<host>

apple-app-site-association文件必须通过HTTPS提供,并且响应必须包含Content-Type: application/json头。

要在iOS模拟器上快速打开应用链接,您可以执行xcrun simctl openurl booted <url>

配置

tauri.conf.json > plugins > deep-link下,配置您想要与您的应用程序关联的域(移动端)和方案(桌面端):

{
  "plugins": {
    "deep-link": {
      "mobile": [
        { "host": "your.website.com", "pathPrefix": ["/open"] },
        { "host": "another.site.br" }
      ],
      "desktop": {
        "schemes": ["something", "my-tauri-app"]
      }
    }
  }
}

用法

首先,您需要向Tauri注册核心插件:

src-tauri/src/lib.rs

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_deep_link::init())  // 注册深度链接插件
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

之后,所有插件的API都可通过JavaScript Guest绑定使用:

import { onOpenUrl } from '@tauri-apps/plugin-deep-link'
await onOpenUrl((urls) => {
  console.log('deep link:', urls)  // 处理深度链接URL
})

请注意,插件仅在macOS、iOS和Android上发出事件。在Windows和Linux上,操作系统将使用URL作为CLI参数生成一个新的应用程序实例。如果您希望您的应用程序在Windows和Linux上的行为与其他平台类似,您可以使用single-instance插件,并启用deep-link功能。

贡献

接受PR。请在提交拉取请求之前确保阅读贡献指南。

贡献者

CrabNebula Impierce

合作伙伴

CrabNebula

有关完整的赞助商列表,请访问我们的网站和Open Collective。

许可证

代码:© 2015 - 现在 - The Commons Conservancy内的Tauri计划。

MIT或MIT/Apache 2.0(如果适用)。

完整示例代码

// src-tauri/src/main.rs
fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_deep_link::init())  // 初始化深度链接插件
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// 前端JavaScript代码
import { onOpenUrl } from '@tauri-apps/plugin-deep-link'

// 监听深度链接事件
await onOpenUrl((urls) => {
  console.log('Received deep link URLs:', urls)
  // 在这里处理深度链接逻辑
  // 例如:解析URL参数、导航到特定页面等
})

// tauri.conf.json 配置示例
{
  "plugins": {
    "deep-link": {
      "mobile": [
        { "host": "myapp.com", "pathPrefix": ["/open"] }
      ],
      "desktop": {
        "schemes": ["my-tauri-app"]
      }
    }
  }
}

基于上述内容,以下是完整的示例demo:

// src-tauri/Cargo.toml
[package]
name = "tauri-deep-link-demo"
version = "0.1.0"
description = "Tauri deep link plugin demo"
authors = ["Your Name"]
license = "MIT"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tauri = { version = "1.0", features = ["api-all"] }
tauri-plugin-deep-link = "2.0.0"  // 深度链接插件

[build-dependencies]
tauri-build = { version = "1.0" }

// src-tauri/src/main.rs
#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_deep_link::init())  // 初始化深度链接插件
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// src-tauri/tauri.conf.json
{
  "build": {
    "beforeDevCommand": "",
    "beforeBuildCommand": "",
    "devPath": "../dist",
    "distDir": "../dist"
  },
  "package": {
    "productName": "DeepLinkDemo",
    "version": "0.1.0"
  },
  "tauri": {
    "allowlist": {
      "all": false,
      "shell": {
        "all": false,
        "open": true
      }
    },
    "bundle": {
      "active": true,
      "targets": "all",
      "identifier": "com.example.tauri-deep-link-demo",
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/128x128@2x.png",
        "icons/icon.icns",
        "icons/icon.ico"
      ]
    },
    "security": {
      "csp": null
    },
    "windows": [
      {
        "fullscreen": false,
        "resizable": true,
        "title": "DeepLinkDemo",
        "width": 800,
        "height": 600
      }
    ],
    "plugins": {
      "deep-link": {
        "mobile": [
          { "host": "myapp.com", "pathPrefix": ["/open"] }
        ],
        "desktop": {
          "schemes": ["my-tauri-app"]
        }
      }
    }
  }
}

// 前端代码 src/main.js
import { onOpenUrl } from '@tauri-apps/plugin-deep-link'

// 监听深度链接事件
async function setupDeepLinkListener() {
  try {
    await onOpenUrl((urls) => {
      console.log('Received deep link URLs:', urls)
      
      // 处理深度链接逻辑
      urls.forEach(url => {
        console.log('Processing URL:', url)
        
        // 解析URL参数
        const urlObj = new URL(url)
        const params = new URLSearchParams(urlObj.search)
        
        // 根据URL路径和参数执行相应操作
        if (urlObj.pathname.includes('/open')) {
          const action = params.get('action')
          const id = params.get('id')
          
          console.log('Action:', action)
          console.log('ID:', id)
          
          // 导航到特定页面或执行特定操作
          handleDeepLinkAction(action, id)
        }
      })
    })
    
    console.log('Deep link listener registered successfully')
  } catch (error) {
    console.error('Failed to register deep link listener:', error)
  }
}

function handleDeepLinkAction(action, id) {
  // 根据action和id执行相应的业务逻辑
  switch (action) {
    case 'view':
      console.log('Opening view for ID:', id)
      // 打开查看页面
      break
    case 'edit':
      console.log('Opening edit for ID:', id)
      // 打开编辑页面
      break
    default:
      console.log('Unknown action:', action)
  }
}

// 初始化应用
document.addEventListener('DOMContentLoaded', () => {
  console.log('App initialized')
  setupDeepLinkListener()
})

// package.json
{
  "name": "tauri-deep-link-demo",
  "version": "0.1.0",
  "description": "Tauri deep link plugin demo",
  "main": "src/main.js",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "tauri": "tauri"
  },
  "dependencies": {
    "@tauri-apps/api": "^1.0.0",
    "@tauri-apps/plugin-deep-link": "^2.0.0"
  },
  "devDependencies": {
    "@tauri-apps/cli": "^1.0.0",
    "vite": "^3.0.0"
  }
}

1 回复

Tauri插件tauri-plugin-deep-link使用指南

插件概述

tauri-plugin-deep-link是一个用于Tauri应用程序的插件,支持深度链接处理和自定义URL协议注册。它允许您的应用响应系统级的URL调用,实现从外部应用或浏览器直接打开您的Tauri应用特定功能。

主要功能

  • 注册自定义URL协议(如:myapp://
  • 处理深度链接调用
  • 跨平台支持(Windows、macOS、Linux)
  • 监听URL打开事件

安装方法

1. 添加依赖

Cargo.toml中添加:

[dependencies]
tauri-plugin-deep-link = "0.1"
serde = { version = "1.0", features = ["derive"] }

2. 注册插件

src/main.rs中:

use tauri_plugin_deep_link;

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_deep_link::init())
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

基本使用方法

1. 注册自定义协议

use tauri::Manager;
use tauri_plugin_deep_link::DeepLinkExt;

#[tauri::command]
async fn register_protocol(app_handle: tauri::AppHandle) -> Result<(), String> {
    app_handle.deep_link().register("myapp").map_err(|e| e.to_string())
}

2. 监听深度链接事件

use tauri::{Manager, Window};
use tauri_plugin_deep_link::DeepLinkExt;

fn setup_deep_link_listener(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
    let app_handle = app.handle();
    let window = app.get_window("main").unwrap();
    
    app_handle.deep_link()
        .on_open(move |url| {
            println!("Received deep link: {}", url);
            // 处理URL逻辑
            handle_deep_link(url, &window);
        });
    
    Ok(())
}

fn handle_deep_link(url: String, window: &Window) {
    // 解析URL并执行相应操作
    if url.starts_with("myapp://open/") {
        let path = url.replace("myapp://open/", "");
        window.eval(&format!("window.location.hash = '#/{}'", path)).unwrap();
    }
}

3. 完整示例

use tauri::{Manager, Window};
use tauri_plugin_deep_link::DeepLinkExt;

#[tauri::command]
async fn init_deep_link(app_handle: tauri::AppHandle, window: Window) -> Result<(), String> {
    // 注册协议
    app_handle.deep_link()
        .register("myapp")
        .map_err(|e| e.to_string())?;
    
    // 设置监听器
    let window_clone = window.clone();
    app_handle.deep_link()
        .on_open(move |url| {
            println!("Deep link received: {}", url);
            
            if let Some(query) = url.strip_prefix("myapp://") {
                match query {
                    "home" => {
                        window_clone.eval("window.location.hash = '#/home'").unwrap();
                    }
                    "settings" => {
                        window_clone.eval("window.location.hash = '#/settings'").unwrap();
                    }
                    _ if query.starts_with("product/") => {
                        let product_id = query.replace("product/", "");
                        window_clone.eval(&format!(
                            "window.location.hash = '#/product/{}'", 
                            product_id
                        )).unwrap();
                    }
                    _ => {}
                }
            }
        });
    
    Ok(())
}

平台特定配置

macOS配置

tauri.conf.json中添加:

{
  "tauri": {
    "bundle": {
      "macOS": {
        "category": "public.app-category.productivity"
      }
    }
  }
}

Windows配置

tauri.conf.json中添加协议注册:

{
  "tauri": {
    "bundle": {
      "windows": {
        "protocols": [
          {
            "name": "MyApp",
            "schemes": ["myapp"]
          }
        ]
      }
    }
  }
}

错误处理

use tauri_plugin_deep_link::DeepLinkError;

fn handle_deep_link_errors() -> Result<(), DeepLinkError> {
    // 错误处理示例
    match app_handle.deep_link().register("myapp") {
        Ok(_) => println!("Protocol registered successfully"),
        Err(DeepLinkError::ProtocolAlreadyRegistered) => {
            eprintln!("Protocol is already registered");
        }
        Err(e) => return Err(e),
    }
    Ok(())
}

注意事项

  1. 在macOS上,需要在应用首次运行时请求权限
  2. Windows需要管理员权限才能注册协议
  3. 协议名称应该保持唯一性,避免与其他应用冲突
  4. 处理完深度链接后应该及时释放资源

这个插件为Tauri应用提供了完整的深度链接解决方案,让您的应用能够更好地与其他应用和系统集成。

完整示例demo

以下是一个完整的Tauri应用示例,展示了如何使用tauri-plugin-deep-link插件:

// src/main.rs
use tauri::{Manager, Window};
use tauri_plugin_deep_link::DeepLinkExt;

// 前端命令:初始化深度链接
#[tauri::command]
async fn init_deep_link(app_handle: tauri::AppHandle, window: Window) -> Result<(), String> {
    // 注册自定义协议
    app_handle.deep_link()
        .register("myapp")
        .map_err(|e| e.to_string())?;
    
    // 克隆窗口用于闭包
    let window_clone = window.clone();
    
    // 设置深度链接监听器
    app_handle.deep_link()
        .on_open(move |url| {
            println!("接收到深度链接: {}", url);
            
            // 解析URL并执行相应操作
            if let Some(query) = url.strip_prefix("myapp://") {
                match query {
                    "home" => {
                        // 导航到首页
                        window_clone.eval("window.location.hash = '#/home'").unwrap();
                    }
                    "settings" => {
                        // 导航到设置页
                        window_clone.eval("window.location.hash = '#/settings'").unwrap();
                    }
                    _ if query.starts_with("product/") => {
                        // 导航到产品详情页
                        let product_id = query.replace("product/", "");
                        window_clone.eval(&format!(
                            "window.location.hash = '#/product/{}'", 
                            product_id
                        )).unwrap();
                    }
                    _ => {
                        // 处理未知链接
                        println!("未知的深度链接: {}", url);
                    }
                }
            }
        });
    
    Ok(())
}

fn main() {
    tauri::Builder::default()
        // 注册深度链接插件
        .plugin(tauri_plugin_deep_link::init())
        // 注册前端命令
        .invoke_handler(tauri::generate_handler![init_deep_link])
        .setup(|app| {
            // 获取主窗口
            let window = app.get_window("main").unwrap();
            
            // 初始化深度链接
            let app_handle = app.handle();
            app_handle.deep_link()
                .register("myapp")
                .expect("无法注册协议");
            
            // 设置深度链接监听器
            let window_clone = window.clone();
            app_handle.deep_link()
                .on_open(move |url| {
                    println!("应用启动时接收到深度链接: {}", url);
                    handle_deep_link(url, &window_clone);
                });
            
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("运行Tauri应用时出错");
}

// 处理深度链接的辅助函数
fn handle_deep_link(url: String, window: &Window) {
    if let Some(query) = url.strip_prefix("myapp://") {
        match query {
            "home" => {
                window.eval("window.location.hash = '#/home'").unwrap();
            }
            "settings" => {
                window.eval("window.location.hash = '#/settings'").unwrap();
            }
            _ if query.starts_with("open/") => {
                let path = query.replace("open/", "");
                window.eval(&format!("window.location.hash = '#/{}'", path)).unwrap();
            }
            _ => {
                println!("未处理的深度链接: {}", url);
            }
        }
    }
}
# Cargo.toml
[package]
name = "my-tauri-app"
version = "0.1.0"
description = "A Tauri app with deep link support"
authors = ["Your Name"]
license = "MIT"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tauri = { version = "1.0", features = ["api-all"] }
tauri-plugin-deep-link = "0.1"

[build-dependencies]
tauri-build = { version = "1.0" }
// tauri.conf.json
{
  "build": {
    "beforeBuildCommand": "",
    "beforeDevCommand": "",
    "devPath": "../dist",
    "distDir": "../dist"
  },
  "package": {
    "productName": "My Tauri App",
    "version": "0.1.0"
  },
  "tauri": {
    "allowlist": {
      "all": false,
      "deep-link": {
        "all": true,
        "register": true,
        "unregister": true,
        "on-open": true
      }
    },
    "bundle": {
      "active": true,
      "category": "DeveloperTool",
      "copyright": "",
      "deb": {
        "depends": []
      },
      "externalBin": [],
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/128x128@2x.png",
        "icons/icon.icns",
        "icons/icon.ico"
      ],
      "identifier": "com.example.my-tauri-app",
      "macOS": {
        "category": "public.app-category.productivity"
      },
      "windows": {
        "certificateThumbprint": null,
        "digestAlgorithm": "sha256",
        "timestampUrl": "",
        "protocols": [
          {
            "name": "MyApp",
            "schemes": ["myapp"]
          }
        ]
      }
    },
    "security": {
      "csp": null
    },
    "updater": {
      "active": false
    },
    "windows": [
      {
        "fullscreen": false,
        "height": 600,
        "resizable": true,
        "title": "My Tauri App",
        "width": 800
      }
    ]
  }
}

这个完整示例展示了如何在Tauri应用中集成深度链接功能,包括协议注册、链接监听和相应的页面导航处理。

回到顶部