人人都会AI编程

主进程与渲染进程双向事件通信

更新时间:2026-07-11

在 Tauri 应用中,“主进程”指的是由 Rust 编写的后端二进制程序,“渲染进程”则是前端页面所在的 WebView。两者运行在相互隔离的环境中,但 Tauri 提供了一套高效、安全且易于使用的机制来实现双向通信。


前端调用后端:命令(Command)

前端通过 invoke 函数调用 Rust 端用 #[tauri::command] 标注的函数,就像调用一个异步 API 一样。

Rust 端定义一个命令:

#[tauri::command]
fn greet(name: String) -> String {
    format!("你好, {}!", name)
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("启动失败");
}

前端调用:

import { invoke } from '@tauri-apps/api/core';
const message = await invoke('greet', { name: 'Tauri' });
console.log(message); // "你好, Tauri!"
  • invoke 返回一个 Promise,异步执行 Rust 函数,不会阻塞 UI。
  • 参数和返回值会自动序列化/反序列化,支持常见类型甚至自定义结构体。
  • 安全边界:命令必须在 invoke_handler 中显式注册,前端无法调用未注册的函数。

后端推送事件到前端:事件系统

当 Rust 端需要主动通知前端(例如下载进度、系统托盘点击、后台任务完成),可以使用事件系统。

Rust 端发射事件:

use tauri::Manager;

#[tauri::command]
async fn start_process<R: tauri::Runtime>(app: tauri::AppHandle<R>) {
    std::thread::spawn(move || {
        // 模拟进度更新
        for i in 1..=100 {
            std::thread::sleep(std::time::Duration::from_millis(50));
            app.emit("progress", i).unwrap();
        }
    });
}

前端监听事件:

import { listen } from '@tauri-apps/api/event';

const unlisten = await listen('progress', (event) => {
    console.log('进度:', event.payload);
    // 更新 UI 进度条
});

// 当组件销毁时取消监听
// unlisten();
  • 事件名可以是任意字符串,事件负载支持序列化。
  • 支持全局事件(所有窗口都能收到)和窗口级事件(仅指定窗口接收)。
  • 前端也可以发射事件到 Rust 端,通过 emit 函数配合 Rust 端的 listen_global 实现反向通信。

前端发射事件到后端

前端:

import { emit } from '@tauri-apps/api/event';
await emit('frontend-event', { message: '用户点击按钮' });

Rust 端监听:

let app_handle = app.handle();
app_handle.listen_global("frontend-event", |event| {
    let payload = event.payload().unwrap();
    println!("收到前端事件: {:?}", payload);
});

通信的基石:安全隔离

无论如何双向通信,Tauri 始终维持着一道硬性边界:

  • 前端代码运行在 WebView 沙箱内,无法直接操作系统资源;
  • 所有交互都必须通过注册的命令或事件,Rust 端有绝对的执行控制权;
  • 敏感 API(如文件读写)必须由开发者显式授权,不存在“后门”。

这种设计让双路通信在极具灵活性的同时,也保证了应用不会因前端漏洞(如 XSS)而导致系统级劫持。


一句话总结:Tauri 用 invoke 实现前端对后端的主动调用,用事件流实现后端的主动推送或前端的反向通知,整个通信过程完全基于安全的 IPC 管道,兼顾了开发的便利性与生产环境的安全性。