# zero_tauri
**Repository Path**: zmmlet/zero_tauri
## Basic Information
- **Project Name**: zero_tauri
- **Description**: tauri 基于webview的桌面端架构,当前实现了基础项目框架,便于熟悉tarui开发和实际项目使用
- **Primary Language**: JavaScript
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-03-25
- **Last Updated**: 2025-09-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Tauri + Vue + TypeScript
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `
```
## 获取系统信息
安装后会自动写入到 package.json 文件和 Cargo.toml 文件,支持 前端 JS 调用和 后端 Rust 调用
- 安装 `pnpm tauri add os`
- Api[https://v2.tauri.org.cn/reference/javascript/os/#arch-1]
## 系统提示对话框
- 安装 `pnpm tauri add dialog`
- Api[https://tauri.app/zh-cn/plugin/dialog/]
报错
```sh
Info Installing NPM dependency "@tauri-apps/plugin-dialog@~2"...
ERR_PNPM_VIRTUAL_STORE_DIR_MAX_LENGTH_DIFF This modules directory was created using a different virtual-store-dir-max-length value. Run "pnpm install" to recreate the modules directory.
Failed to install NPM dependency
Error Failed to install NPM dependency
ELIFECYCLE Command failed with exit code 1.
```
解决方法
npm install -g pnpm
## 1自定义托盘
1. 添加配置 src-tauri\tauri.conf.json
```json
"app": {
"windows": [
],
"trayIcon": {
"iconPath": "icons/icon.ico",
"iconAsTemplate": true,
"title": "时间管理器",
"tooltip": "时间管理器"
}
},
```
2. 添加自定义图标权限 src-tauri\Cargo.toml
```toml
[dependencies]
tauri = { version = "2", features = ["tray-icon", "image-png"] }
```
3. 创建自定义托盘
- 3.1 src-tauri\src\tray.rs
```rs
use tauri::{
menu::{Menu, MenuItem, Submenu},
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
Manager,
Runtime,
};
pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> {
let quit_i = MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?;
let show_i = MenuItem::with_id(app, "show", "显示", true, None::<&str>)?;
let hide_i = MenuItem::with_id(app, "hide", "隐藏", true, None::<&str>)?;
let edit_i = MenuItem::with_id(app, "edit_file", "编辑", true, None::<&str>)?;
let new_i = MenuItem::with_id(app, "new_file", "添加", true, None::<&str>)?;
let a =Submenu::with_id_and_items(app, "File", "文章", true, &[&new_i, &edit_i])?;
// 分割线
let menu = Menu::with_items(app, &[&quit_i, &show_i, &hide_i, &a])?;
// 创建系统托盘
let _ = TrayIconBuilder::with_id("tray")
// 添加托盘图标
.icon(app.default_window_icon().unwrap().clone())
// 添加菜单
.menu(&menu)
// 禁用鼠标左键点击图标显示托盘菜单
.show_menu_on_left_click(false)
// 监听事件菜单
.on_menu_event(move |app, event| match event.id.as_ref() {
"quit" => {
app.exit(0);
},
"show" => {
let window = app.get_webview_window("main").unwrap();
let _ = window.show();
},
"hide" => {
let window = app.get_webview_window("main").unwrap();
let _ = window.hide();
},
"edit_file" => {
println!("edit_file");
},
"new_file" => {
println!("new_file");
},
// Add more events here
_ => {}
})
// 监听托盘图标发出的鼠标事件
.on_tray_icon_event(|tray, event| {
// 左键点击托盘图标显示窗口
if let TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
} = event
{
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
})
.build(app);
Ok(())
}
```
-3.2 在 src-tauri\src\lib.rs 文件中引用
```rs
#[cfg(desktop)]
mod tray;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
// 添加自定义托盘
.setup(|app| {
#[cfg(all(desktop))]
{
let handle = app.handle();
tray::create_tray(handle)?;
}
Ok(())
})
// 引用插件
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
## 1托盘图标闪烁
1. 托盘事件定义 tray.rs
```rs
use tauri::{
menu::{Menu, MenuItem, Submenu},
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
Manager, Runtime,
};
pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> {
let quit_i = MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?;
let show_i = MenuItem::with_id(app, "show", "显示", true, None::<&str>)?;
let hide_i = MenuItem::with_id(app, "hide", "隐藏", true, None::<&str>)?;
let edit_i = MenuItem::with_id(app, "edit_file", "编辑", true, None::<&str>)?;
let new_i = MenuItem::with_id(app, "new_file", "添加", true, None::<&str>)?;
let a = Submenu::with_id_and_items(app, "File", "文章", true, &[&new_i, &edit_i])?;
// 分割线
let menu = Menu::with_items(app, &[&quit_i, &show_i, &hide_i, &a])?;
// 创建系统托盘 let _ = TrayIconBuilder::with_id("icon")
let _ = TrayIconBuilder::with_id("tray")
// 添加菜单
.menu(&menu)
// 添加托盘图标
.icon(app.default_window_icon().unwrap().clone())
.title("zero")
.tooltip("zero")
.show_menu_on_left_click(false)
// 禁用鼠标左键点击图标显示托盘菜单
// .show_menu_on_left_click(false)
// 监听事件菜单
.on_menu_event(move |app, event| match event.id.as_ref() {
"quit" => {
app.exit(0);
}
"show" => {
let window = app.get_webview_window("main").unwrap();
let _ = window.show();
}
"hide" => {
let window = app.get_webview_window("main").unwrap();
let _ = window.hide();
}
"edit_file" => {
println!("edit_file");
}
"new_file" => {
println!("new_file");
}
// Add more events here
_ => {}
})
// 监听托盘图标发出的鼠标事件
.on_tray_icon_event(|tray, event| {
// 左键点击托盘图标显示窗口
if let TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
} = event
{
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
})
.build(app);
Ok(())
}
```
2. lib.rs 使用
```rs
#[cfg(desktop)]
mod tray;
// 自定义函数声明
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_log::Builder::new().build())
// 添加自定义托盘
.setup(|app| {
#[cfg(all(desktop))]
{
let handle: &tauri::AppHandle = app.handle();
tray::create_tray(handle)?;
}
Ok(())
})
// Run the app
// 注册 Rust 后端函数,暴露给前端调用
.invoke_handler(tauri::generate_handler![
greet
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
3. 调用托盘事件
```vue
```
## http
1. 依赖安装`pnpm tauri add http`
2. 权限配置 src-tauri\capabilities\default.json
```json
{
"permissions": [
"core:default",
"opener:default",
{
"identifier": "http:default",
"allow": [
{
"url": "http://**"
},
{
"url": "https://**"
},
{
"url": "http://*:*"
},
{
"url": "https://*:*"
}
]
}
]
}
```
3. vite.config.json 配置代理
```ts
import { ConfigEnv, defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "node:path";
import { fileURLToPath, URL } from "node:url";
const host = process.env.TAURI_DEV_HOST;
export default defineConfig(({ mode }: ConfigEnv) => {
const config = loadEnv(mode, process.cwd());
return {
// ......
server: {
//配置跨域
proxy: {
"/tick-basic": {
// “/api” 以及前置字符串会被替换为真正域名
target: config.VITE_SERVICE_URL, // 请求域名
changeOrigin: true, // 是否跨域
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
port: 1420,
strictPort: true,
host: host || false,
cors: true, // 配置 CORS
hmr: host
? {
protocol: "ws",
host,
port: 1421,
}
: undefined,
watch: {
ignored: ["**/src-tauri/**"],
},
},
};
});
```
4. 请求封装
5. 使用封装请求
## 文件上传下载
1. 依赖安装 `pnpm tauri add upload`
## SQL
1. 依赖安装`pnpm tauri add sql`
2. 在 src-tauri 目录下执行 `cargo add tauri-plugin-sql --features sqlite`
## UI 库
```sh
pnpm add unplugin-auto-import unplugin-vue-components naive-ui -D
```
```sh
pnpm add vue-router@4
```
```sh
pnpm add pinia pinia-plugin-persistedstate pinia-shared-state
```
```sh
pnpm add @rollup/plugin-terser --dev
pnpm add @codecov/vite-plugin --save-dev
```
```sh
pnpm add eslint@latest eslint-plugin-vue@latest -D
pnpm add prettier@latest -D
```
天文计算:使用 astronomy-engine 或 suncalc 来计算行星位置和天象。
农历和节气:使用 lunar-javascript 或 chinese-lunar 来计算农历日期和节气。
```sh
pnpm add lunar-typescript
pnpm add astronomy-engine
```
## TODO 多窗口
## TODO 发版更新提示
## TODO 启动画面
https://blog.csdn.net/sxlesq/article/details/145112068?spm=1001.2014.300
src-tauri\tauri.conf.json
```json
"app": {
"windows": [
{
"title": "tauri_demo",
"width": 800,
"height": 600,
"center": true,
"fullscreen": false,
"resizable": true,
"minWidth": 800,
"minHeight": 600,
"visible": false
},
{
"label": "start",
"url": "/start.html",
"center": true,
"width": 1200,
"height": 800
}
],
"security": {
"csp": null
}
},
```
## Android环境变量配置
Tauri 开发 Android 应用:环境搭建与入门指南[https://www.kucoding.com/article/259.html]
ANDROID_HOME
C:\Users\yu\AppData\Local\Android\Sdk
JAVA_HOME
C:\Program Files\Android\Android Studio\jbr
NDK_HOME
C:\Users\yu\AppData\Local\Android\Sdk\ndk\27.0.12077973
注意:需要开启,windows11 开发者模式,否则没有调试权限,启动报错
所需要的 JVM 版本大于实际安装版本
```sh
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':buildSrc:compileKotlin'.
> Could not resolve all files for configuration ':buildSrc:compileClasspath'.
> Could not resolve com.android.tools.build:gradle:8.5.1.
Required by:
project :buildSrc
> Dependency requires at least JVM runtime version 11. This build uses a Java 8 JVM.
* Try:
> Run this build using a Java 11 or newer JVM.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 1s
ELIFECYCLE Command failed with exit code 4294967295.
```
打包数字证书配置
## 更新
密钥密码 zero
1. 安装 `pnpm tauri add updater`
```mermaid
graph LR
[ 外部网络 ]
│
▼
[ 边界防火墙 ]
│
▼
[ 入站流量层 ]
├─ [反向代理集群](如Nginx/HAProxy)
└─ [API网关](如Kong/Spring Cloud Gateway)
│
▼
[ 网络安全平台 ]
├─ 防火墙(区域隔离)
├─ IDS/IPS(入侵检测防御)
├─ WAF(Web应用防火墙)
└─ 流量审计系统
│
▼
[ DMZ区 ]
├─ 公共服务集群
│ ├─ 认证服务(OAuth2/Keycloak)
│ └─ 缓存服务(Redis集群)
│
└─ [出站代理服务器](Squid/正向代理)
│
▼
[ 内部防火墙 ]
│
▼
[ 内网服务层 ]
├─ [内网API网关](服务路由)
├─ 微服务集群(Docker/K8s Pods)
├─ 数据库集群(主从隔离)
└─ 消息队列(Kafka/RabbitMQ)
│
▼
[ 内部安全审计 ]
├─ 日志聚合(ELK/Grafana)
└─ 行为监控(SIEM系统)
```
入站请求路径:
客户端 → 边界防火墙(仅放行HTTPS) → 反向代理(URL路由) → WAF(过滤SQLi/XSS) → API网关(鉴权) → 内网微服务 → 数据库
出站请求路径:
内网服务 → 出站代理(域名白名单) → IPS(检测C2通信特征) → 流量审计(记录完整Payload) → 外部API
## 会议系统
系统架构图
```mermaid
graph TD
subgraph 客户端
A[Tauri桌面应用] -->|WebRTC媒体流| B((会议房间))
A -->|WebSocket协议| C[信令服务器]
A -->|SIP协议| F[FreeSWITCH服务器]
A -->|Vue3+TS UI| D[用户界面]
end
subgraph 服务端
C -->|控制信令| E[FreeSWITCH服务器]
E -->|SIP协议| F
E -->|RTP/RTCP媒体流| B
E -->|数据库操作| G[(数据库)]
F -->|SIP中继| H[外部PSTN/SIP网络]
end
```
技术架构图
```mermaid
graph LR
subgraph 客户端技术栈
A1[Tauri Core] --> A2[Rust后端]
A1 --> A3[WebView渲染]
A3 --> A4[Vue3+TS]
A4 --> A5[WebRTC API]
A4 --> A6[WebSocket Client]
A4 --> A7[SIP.js]
end
subgraph 信令服务
B1[Node.js/Go] --> B2[WebSocket Server]
B2 --> B3[信令路由]
B3 --> B4[FreeSWITCH ESL]
end
subgraph 媒体服务
C1[FreeSWITCH] --> C2[会议模块]
C1 --> C3[WebRTC网关]
C1 --> C4[SIP协议栈]
C1 --> C5[RTP引擎]
end
subgraph 基础设施
D1[PostgreSQL] --> D2[用户数据]
D2 --> D3[会议记录]
D4[STUN/TURN] --> D5[NAT穿透]
end
```
技术架构说明
客户端层
复制
┌───────────────────────┐
│ Tauri应用架构 │
├──────────┬────────────┤
│ Rust层 │ WebView层 │
│ (系统交互)│ Vue3+TS │
│ │ WebRTC API │
│ │ SIP.js │
│ │ WebSocket │
└──────────┴────────────┘
Tauri框架:使用Rust处理原生系统交互,WebView承载Vue界面
Vue3+TS:采用组合式API+TypeScript实现响应式UI
WebRTC:处理音视频采集、编解码、网络传输
SIP.js:实现SIP协议栈对接传统电话系统
WebSocket:与信令服务器保持长连接
信令服务层
复制
┌──────────────────────────────┐
│ 信令服务器功能模块 │
├─────────────┬────────────────┤
│ 连接管理 │ 信令路由 │
│ 房间状态同步│ FreeSWITCH控制 │
│ 安全认证 │ 事件日志 │
└─────────────┴────────────────┘
采用Node.js/Go语言开发
实现信令路由、状态同步、权限验证
通过ESL(Event Socket Library)控制FreeSWITCH
媒体服务层
复制
┌──────────────────────────────┐
│ FreeSWITCH核心功能 │
├──────────────┬───────────────┤
│ 会议管理 │ SIP协议栈 │
│ 媒体路由 │ WebRTC网关 │
│ 混流服务 │ 录音录像 │
│ DTMF处理 │ 编解码转换 │
└──────────────┴───────────────┘
支持多种编解码器(OPUS/H264/VP8)
提供会议混音、视频合屏功能
实现WebRTC与传统SIP的协议互通
协议交互流程
用户通过Vue界面发起呼叫
WebSocket发送SDP Offer到信令服务器
信令服务器通过ESL创建FreeSWITCH会议
FreeSWITCH通过SIP协议与终端建立连接
WebRTC ICE协商完成P2P媒体传输
通话质量监控通过RTCP反馈实现
关键技术组合
WebRTC+FreeSWITCH:通过mod_verto模块实现浏览器端WebRTC接入
SIP协议集成:使用RFC7118规范实现WebRTC与SIP的SDP转换
Tauri优化:使用Rust实现高性能的屏幕共享采集
QoS保障:采用TWCC协议实现网络拥塞控制
建议在具体实现时:
使用mediasoup替代原生WebRTC以获得更好的SFU控制
采用Kurento实现高级媒体处理功能
集成Janus Gateway实现更好的协议转换支持