Skip to content

从前端调用 Rust 函数

前置条件

rust 函数返回给前端的所内容都必须实现 serde::Serialize,包括错误。

因为前端只接收 Json 格式的数据。

注意:大多数错误类型都没有实现它(包括 Rust 的 std 库)。在简单的场景中,可以使用 map_err 将这些错误转换为 String。

基础示例

  1. 使用属性宏,并定义一个函数(在前端,这个函数被叫做“命令”)
  2. 向 Tarui 构建器函数提供命令列表
  3. 在前端使用 JS 即可调用
rust
#[tauri::command]
fn my_custom_command() {
  println!("I was invoked from JavaScript!");
}
rust
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
  tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![my_custom_command])    
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}
js
// 使用 Tauri API npm 包时:
import { invoke } from '@tauri-apps/api/core';

// 使用 Tauri 全局脚本(不使用 npm 包时)
// 确保在 `tauri.conf.json` 中设置 `app.withGlobalTauri` 为 true
const invoke = window.__TAURI__.core.invoke;

// 调用命令
invoke('my_custom_command');

在独立模块里写函数(命令)

将 rs 代码分组,避免使 lib.rs 文件变得臃肿。

rust
// 在 src-tauri/src/commands.rs 文件中定义一个函数(命令):
#[tauri::command]
pub fn my_custom_command() {
  println!("I was invoked from JavaScript!");
}
rust
// 在 lib.rs 文件中,定义模块并相应地提供函数(命令)列表

mod commands;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
  tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![commands::my_custom_command])  
    // commands:: 前缀是包括在命令函数的完整路径里的。
    // 因为 Tauri 规定所有命令(也就是rust提供的函数)不能重名,
    // 所以在前端可以省略 commands:: 前缀,还是这样子调用命令 invoke("my_custom_command")
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}

WASM

传递参数

在 Tauri 中,参数名的命名规则是由 Rust 代码决定的,但在前端调用时,Rust 中的 snake_case 在 JavaScript 中就要使用 camelCase。

另外,前端传递参数时,需要使用 Json 格式。

rust
// Rust 后端 - 参数使用 snake_case
#[tauri::command]
fn greet_user(user_name: String, user_age: u32) -> String {
    format!("Hello {}, age {}", user_name, user_age)
}
js
// 前端使用 camelCase
invoke('greet_user', { 
    userName: 'Alice',    // 注意:这里是 userName,不是 user_name
    userAge: 25           // 注意:这里是 userAge,不是 user_age
});

返回数据

rust 后端可以返回数据

rust
#[tauri::command]
fn my_custom_command() -> String {
  "Hello from Rust!".into()
}
js
invoke('my_custom_command').then((message) => console.log(message));

返回数组缓冲区

错误处理

支持让函数返回 Result :

rust
#[tauri::command]
fn login(user: String, password: String) -> Result<String, String> {
  if user == "tauri" && password == "tauri" {
    // resolve
    Ok("logged_in".to_string())
  } else {
    // reject
    Err("invalid credentials".to_string())
  }
}
js
invoke('login', { user: 'tauri', password: '0j4rijw8=' })
  .then((message) => console.log(message))
  .catch((error) => console.error(error));