当前位置: 首页 > news >正文

【一起学Rust | Tauri2.0框架】单实例应用程序的深入解析:零漏洞实现与优化实战

文章目录

  • 前言
  • 一、 单实例应用的意义
  • 二、 实现单实例应用的方法
    • 1 Windows下的实现
      • 1.1 创建命名Mutex
      • 1.2 在Tauri应用中集成Mutex检查
    • 2 macOS下的实现
      • 2.1 获取Bundle Identifier
      • 2.2 检查是否已经有实例在运行
    • 3 Linux下的实现
      • 3.1 获取进程列表
      • 3.2 检查是否已经有实例在运行
    • 4 在Tauri应用中集成单实例检查
  • 三、使用Tauri官方提供的插件实现单例程序
    • 1. 安装准备
    • 2. 自动安装(推荐)
    • 3. 手动安装
  • 四、配置单例插件
    • 1. `init`函数
    • 2. 新打开程序提示例子


前言

随着跨平台应用开发的需求不断增加,Tauri2.0框架凭借其高性能和跨平台的特性,成为了开发者们的热门选择。然而,在开发桌面应用时,如何确保应用程序只能运行一个实例是一个常见的需求。例如,某些应用程序需要独占系统资源,或者需要避免用户误操作导致的数据冲突。今天,我们将探讨如何在Tauri2.0框架下,使用Rust语言实现单实例应用程序的功能。

本文将详细介绍在不同操作系统(Windows、macOS、Linux)下实现单实例应用的方法,并提供完整的代码示例。通过本文,你将了解到如何在Tauri2.0应用启动时检查是否已经有实例在运行,并采取相应的措施,例如提示用户或将参数传递给已有的实例。

最后再为你介绍Tauri官方为我们实现这种需求提供的一种捷径,从而不用去管理互斥体,而是简单的插件配置就能得到相同的结果,这也是为什么要写本文的原因。这就是Tauri插件 —— Single Instance.


一、 单实例应用的意义

在开发桌面应用时,单实例应用的意义主要体现在以下几个方面:

  1. 资源管理:某些应用程序需要独占特定的系统资源,例如硬件设备或独特的系统服务。如果允许多个实例运行,可能会导致资源争抢或不可预测的行为。

  2. 数据一致性:对于需要处理共享数据的应用程序,例如数据库管理工具或配置文件编辑器,防止多个实例同时修改数据可以避免数据冲突和不一致。

  3. 用户体验:在某些场景下,用户可能不小心多次启动应用程序,导致多个实例运行。通过单实例机制,可以提供更友好的用户体验,例如自动将焦点切换到已有的实例。

  4. 安全性:对于某些需要严格控制的应用程序,例如金融类软件或敏感数据处理工具,单实例机制可以增强应用的安全性,防止恶意的多实例攻击。

二、 实现单实例应用的方法

在Tauri2.0框架下实现单实例应用,我们需要在应用启动时检查是否已经有一个实例在运行。如果有,则采取相应的措施,例如提示用户或将参数传递给已有的实例。

1 Windows下的实现

在Windows平台下,可以通过创建一个命名的Mutex(互斥量)来实现单实例检查。Mutex是Windows提供的一种同步机制,可以用于跨进程的同步和互斥控制。

1.1 创建命名Mutex

在Windows下,我们可以通过调用CreateMutexW函数创建一个命名的Mutex。如果Mutex已经存在,则表示已经有一个实例在运行。

use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::synchapi::CreateMutexW;fn create_mutex(name: &str) -> bool {let name = OsStr::new(name).encode_wide().chain(Some(0)).collect::<Vec<u16>>();unsafe {CreateMutexW(name.as_ptr(), false as DWORD, None) as DWORD} != 0
}fn is_single_instance(name: &str) -> bool {let result = create_mutex(name);if result {// 如果Mutex已经存在,则表示已经有一个实例在运行unsafe {if GetLastError() == 183 { // ERROR_ALREADY_EXISTSreturn false;}}}result
}

1.2 在Tauri应用中集成Mutex检查

在Tauri应用的主函数中,我们可以调用上述函数来检查是否已经有一个实例在运行。如果已经有实例运行,则可以提示用户并退出。

fn main() {let instance_name = "MyTauriApp";if !is_single_instance(instance_name) {// 如果已经有一个实例在运行,则提示用户并退出println!("An instance of {} is already running.", instance_name);std::process::exit(1);}// 启动Tauri应用tauri::run();
}

2 macOS下的实现

在macOS平台下,可以通过BUNDLE_IDENTIFIER来实现单实例检查。macOS提供了LSOpenURLsWithRole函数,可以用于检查是否已经有一个应用程序在运行。

2.1 获取Bundle Identifier

在macOS下,每个应用程序都有一个唯一的Bundle Identifier,可以通过Info.plist文件配置。

use std::process::Command;fn get_bundle_identifier() -> String {let output = Command::new("osascript").arg("-e").arg("id of app \"System Events\"").output().expect("failed to execute osascript");String::from_utf8(output.stdout).unwrap()
}

2.2 检查是否已经有实例在运行

通过调用LSOpenURLsWithRole函数,我们可以检查是否已经有一个实例在运行。如果有,则返回true,否则返回false

use std::os::raw::c_char;extern crate libc;fn is_single_instance(bundle_id: &str) -> bool {let mut psi: libc::PROCESSENTRY32 = unsafe { std::mem::zeroed() };let snapshot = unsafe { libc::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };if snapshot == 0 {return false;}psi.dwSize = std::mem::size_of::<libc::PROCESSENTRY32>() as DWORD;while unsafe { Process32Next(snapshot, &mut psi) } != 0 {if let Some(name) = unsafe { CStr::from_ptr(psi.szExeFile.as_ptr() as *const c_char) }.to_str() {if name == bundle_id {return true;}}}unsafe { CloseHandle(snapshot) };false
}

3 Linux下的实现

在Linux平台下,可以通过检查进程名或使用套接字来实现单实例检查。这里我们将演示如何通过检查进程名来实现单实例检查。

3.1 获取进程列表

通过调用/proc文件系统,我们可以获取当前运行的所有进程,并检查是否有相同的进程名。

use std::fs;
use std::path::Path;fn get_process_list() -> Vec<String> {let mut processes = Vec::new();for entry in fs::read_dir("/proc").unwrap() {let entry = entry.unwrap();let path = entry.path();if path.is_dir() {if let Some(name) = path.file_name().and_then(|n| n.to_str()) {if name.chars().all(char::is_digit) {processes.push(name.to_string());}}}}processes
}

3.2 检查是否已经有实例在运行

通过遍历所有进程,并检查是否有相同的进程名来判断是否已经有实例在运行。

fn is_single_instance(process_name: &str) -> bool {let processes = get_process_list();for pid in processes {let exe_path = format!("/proc/{}/exe", pid);let exe_link = Path::new(&exe_path);if exe_link.exists() {if let Some(exe_path) = exe_link.canonicalize().ok() {if exe_path.file_name().and_then(|n| n.to_str()) == Some(process_name) {return true;}}}}false
}

4 在Tauri应用中集成单实例检查

在Tauri应用的主函数中,我们可以根据不同的平台调用相应的单实例检查函数。

fn main() {#[cfg(target_os = "windows")]{let instance_name = "MyTauriApp";if !is_single_instance(instance_name) {println!("An instance of {} is already running.", instance_name);std::process::exit(1);}}#[cfg(target_os = "macos")]{let bundle_id = get_bundle_identifier();if is_single_instance(&bundle_id) {println!("An instance of {} is already running.", bundle_id);std::process::exit(1);}}#[cfg(target_os = "linux")]{let process_name = "my_tauri_app";if is_single_instance(process_name) {println!("An instance of {} is already running.", process_name);std::process::exit(1);}}tauri::run();
}

三、使用Tauri官方提供的插件实现单例程序

1. 安装准备

首先,确保你安装的Rust版本符合条件,该插件要求你的Rust版本大于1.77.2.

然后就是看你的应用平台是否支持该插件,官方给出以下表格

在这里插入图片描述
可以明显看到,只有桌面系统受支持,也就是你的应用只能是在windows,linux,macos上,这个插件才会有用,否则插件是用不了的。

2. 自动安装(推荐)

使用你所选择的包管理器直接安装即可,例如pnpm安装

pnpm tauri add single-instance

3. 手动安装

首先添加依赖

# src-tauri/Cargo.toml
[dependencies]
tauri-plugin-single-instance = "2.0.0"

然后在tauri启动的时候添加插件

pub fn run() {tauri::Builder::default()// 就是下面这行.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {})) .run(tauri::generate_context!()).expect("error while running tauri application");
}

然后运行一下项目就装好插件了

pnpm tauri dev

四、配置单例插件

如果你只是想要简单的实现单实例的话,就以上安装配置就已经能够达到这个效果了,如果你还想要在这个过程中实现其他功能,例如用户启动了另一个程序后提示程序已经启动了,那么可以接着往下看。

1. init函数

在配置安装插件时有一个init函数可以注意一下,也就是

.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {// 在这里写代码 ……
}))

插件的 init() 方法接收一个闭包,该闭包在新 App 实例启动时调用,但由插件关闭。 这个闭包有三个参数:

  1. app:应用程序的 AppHandle ,即应用的句柄,用来操作该程序。
  2. args:用户初始化新实例时传递的参数列表,也就是新打开的程序的传入参数。
  3. cwd:当前工作目录表示启动新应用程序实例的目录,也就是另一个程序在哪个目录打开的。

2. 新打开程序提示例子

注意,这部分逻辑你可以自己实现,这只是个官方给的例子。

use tauri::{AppHandle, Manager};pub fn run() {tauri::Builder::default().plugin(tauri_plugin_single_instance::init(|app, args, cwd| {let _ = show_window(app);})).run(tauri::generate_context!()).expect("error while running tauri application");
}fn show_window(app: &AppHandle) {let windows = app.webview_windows();windows.values().next().expect("Sorry, no window found").set_focus().expect("Can't Bring Window to Focus");
}

相关文章:

【一起学Rust | Tauri2.0框架】单实例应用程序的深入解析:零漏洞实现与优化实战

文章目录 前言一、 单实例应用的意义二、 实现单实例应用的方法1 Windows下的实现1.1 创建命名Mutex1.2 在Tauri应用中集成Mutex检查 2 macOS下的实现2.1 获取Bundle Identifier2.2 检查是否已经有实例在运行 3 Linux下的实现3.1 获取进程列表3.2 检查是否已经有实例在运行 4 在…...

PhyloSuite v1.2.3安装与使用-生信工具049

PhyloSuite 一个好用的win集成建树平台&#xff0c;官方相关文档视频等做的可好了PhyloSuite (jushengwu.com) 官网 https://github.com/dongzhang0725/PhyloSuite/releases #官网 http://phylosuite.jushengwu.com/dongzhang0725.github.io/installation/ #官方说明文档…...

使用Apache Lucene构建高效的全文搜索服务

使用Apache Lucene构建高效的全文搜索服务 在现代应用程序中&#xff0c;全文搜索功能是不可或缺的一部分。无论是电子商务网站、内容管理系统&#xff0c;还是数据分析平台&#xff0c;快速、准确地搜索大量数据是提升用户体验的关键。Apache Lucene 是一个强大的全文搜索引擎…...

SSH远程登录并执行命令

SSH远程登录并执行命令 1、登录远程服务器2、远程执行命令3、远程执行交互命令4、远程执行脚本5、退出远程SSH连接 SSH是Linux中的远程连接管理工具&#xff0c;可以在本地服务器上通过SSH协议连接到远程服务器&#xff0c;并在远程服务器上执行命令 SSH不仅可以用来登录远程服…...

EasyRTC:支持任意平台设备的嵌入式WebRTC实时音视频通信SDK解决方案

随着互联网技术的飞速发展&#xff0c;实时音视频通信已成为各行各业数字化转型的核心需求之一。无论是远程办公、在线教育、智慧医疗&#xff0c;还是智能安防、直播互动&#xff0c;用户对低延迟、高可靠、跨平台的音视频通信需求日益增长。 一、WebRTC与WebP2P&#xff1a;实…...

Golang语言特性

1.Go语言的优势 1.1极简单的部署方式 —可以直接编译成机器码。代码可以直接转换为二进制数据&#xff0c;在操作系统上可以直接./去执行。 —不依赖其他库。最终生成的可执行程序是一个静态的二进制文本文件。 —可以直接运行即可部署。 —静态类型语言。编译的时候检查出来隐…...

LangPrompt提示词

LangPrompt提示词 https://github.com/langgptai/LangGPT 学习LangGPT的仓库&#xff0c;帮我创建 一个专门生成LangGPT格式prompt的助手 根据LangGPT的格式规范设计的专业提示词生成助手框架。以下是分步骤的解决方案&#xff1a; 助手角色定义模板 # Role: LangGPT提示词架…...

Java 容器之 List

在 Java 的集合框架中&#xff0c;List 是 Collection 的重要子接口&#xff0c;以其有序、可重复的特点广泛应用于开发中。本文将详细探讨 List 的核心概念、主要实现类&#xff08;如 ArrayList 和 LinkedList&#xff09;的底层原理&#xff0c;以及使用中需要注意的常见问题…...

ETL-kettle数据转换使用详解

一、excel转换成mysql 表格就按照我们刚才转换的表格来转换成MySQL数据 在MySQL数据库中创建数据库&#xff0c;这个根据自身情况。我就在现有test库中测试了。 根据以上步骤&#xff0c;新建转换。 构建流程图&#xff0c;选择excel输入和表输出 将两个组件连接起来 双击…...

【容器化】低版本docker拉取ubuntn 22.04镜像启动容器执行apt update提示 NO_PUBKEY 871920D1991BC93C

前置信息 宿主机信息 [root@localhost ~]# cat /etc/os-release NAME="CentOS Linux" VERSION="7 (Core)" ID="centos" ID_LIKE="rhel fedora" VERSION_ID="7" PRETTY_NAME="CentOS Linux 7 (Core)" ANSI_COLOR…...

Hive-04之存储格式、SerDe、企业级调优

一、主题 hive表的数据压缩和文件存储格式hive的自定义UDF函数hive的JDBC代码操作hive的SerDe介绍和使用hive的优化 二、要点 1. hive表的文件存储格式 Hive支持的存储数的格式主要有&#xff1a;TEXTFILE&#xff08;行式存储&#xff09; 、SEQUENCEFILE(行式存储)、ORC&…...

Makefile、Make和CMake:构建工具的三剑客

目录 1. Makefile 2. Make 3. CMake Makefile、Make、CMake的关系 在软件开发中&#xff0c;构建工具是必不可少的。它们帮助开发者自动化编译、链接和打包的过程&#xff0c;确保代码能够高效地转化为可执行文件。Makefile、Make和CMake是三个常见的构建工具&#xff0c;它…...

The “Rule-of-Zero“ should be followed (s4963)

Most classes should not directly handle resources, but instead, use members that perform resource handling for them: For memory, it can be std::unique_ptr, std::shared_ptr, std::vector…​For files, it can be std::ofstream, std::ifstream…​…​ Classes …...

Kotlin语言特性(二):泛型与注解

Kotlin语言特性(二):泛型与注解 一、引言 在上一篇文章中,我们介绍了Kotlin的三大核心特性。本文将深入探讨Kotlin的泛型和注解特性,并与Java进行对比,帮助你更好地理解和运用这些特性。 二、Kotlin泛型 2.1 泛型基础 2.1.1 声明泛型类 // Kotlin泛型类声明 class …...

FunPapers[3]:WWW‘25「快手」生成式回归预测观看时长

Sequence Generation Modeling for Continuous Value Prediction https://arxiv.org/pdf/2412.20211&#xff0c;www 2025. 文章目录 Sequence Generation Modeling for Continuous Value Prediction核心思想1. CVP常规方法是怎么做的&#xff1f;2. 观看时长预测和CVP是如何关…...

并发编程1

JAVA线程回顾 多线程 多个并行的线程来完成个自的任务&#xff0c;优点是程序响应速度更快&#xff0c;程序性能得到提升。 并行执行与并发执行 并发执行就是在单核CPU下&#xff0c;现成实际上是串行执行的&#xff0c;任务调度器将cpu的时间片分给不同的线程使用&#xff0…...

Hadoop之01:HDFS分布式文件系统

HDFS分布式文件系统 1.目标 理解分布式思想学会使用HDFS的常用命令掌握如何使用java api操作HDFS能独立描述HDFS三大组件namenode、secondarynamenode、datanode的作用理解并独立描述HDFS读写流程HDFS如何解决大量小文件存储问题 2. HDFS 2.1 HDFS是什么 HDFS是Hadoop中的一…...

从源到目标:深度学习中的迁移学习与领域自适应实践

云边有个稻草人-CSDN博客 目录 引言 一、迁移学习概述 1.1 迁移学习的类型 1.2 迁移学习的核心思想 1.3 迁移学习的应用场景 二、领域自适应&#xff08;Domain Adaptation&#xff09; 2.1 领域自适应的定义 2.2 领域自适应的挑战 2.3 领域自适应的核心方法 &#…...

WebRTC与PJSIP:呼叫中心系统技术选型指南

助力企业构建高效、灵活的通信解决方案 在数字化时代&#xff0c;呼叫中心系统的技术选型直接影响客户服务效率和业务扩展能力。WebRTC与PJSIP作为两大主流通信技术&#xff0c;各有其核心优势与适用场景。本文从功能、成本、开发门槛等维度为您深度解析&#xff0c;助您精准匹…...

使用IDEA如何隐藏文件或文件夹

选择file -> settings 选择Editor -> File Types ->Ignored Files and Folders (忽略文件和目录) 点击号就可以指定想要隐藏的文件或文件夹...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...