Skip to main content

3 posts tagged with "Tauri"

View All Tags

在现代桌面应用开发中,Tauri 框架凭借其轻量级、高性能和安全性,成为开发者们构建跨平台应用的首选工具之一。Tauri 允许开发者使用现代前端框架(如 React、Vue 或 Svelte)构建用户界面,同时利用 Rust 语言处理高效且安全的后端逻辑。然而,前后端之间的高效通信是构建功能丰富且稳定的 Tauri 应用的关键。本文将详细介绍 Tauri 中前后端通信的主要方式——Commands(命令)Events(事件)Channels(通道),并通过示例代码帮助您更好地理解和应用这些技术。

目录

  1. Tauri 简介
  2. 前后端通信方式概述
  3. Commands、Events 与 Channels 的对比
  4. 示例代码
  5. 权限配置示例
  6. 错误处理
  7. 最佳实践与安全性
  8. 性能优化
  9. 实际案例
  10. 总结
  11. 参考资源

Tauri 简介

Tauri 是一个用于构建跨平台桌面应用的框架,支持 WindowsmacOSLinux。它利用前端技术(如 HTML、CSS、JavaScript)构建用户界面,并使用 Rust 处理后端逻辑。与 Electron 相比,Tauri 生成的应用体积更小,性能更优,且具备更高的安全性。

前后端通信方式概述

在 Tauri 框架中,前端(通常使用 JavaScript 框架如 React、Vue 或 Svelte)与后端(Rust 编写)之间的通信是实现应用功能的核心。Tauri 提供了多种通信机制,主要包括 Commands(命令)Events(事件)Channels(通道)。除此之外,还有一些其他的通信方式,如在 Rust 中执行 JavaScript 代码。以下将详细介绍这些通信方式、它们的区别及适用场景。

Commands(命令)

Commands 是前端调用后端 Rust 函数的主要方式。通过命令,前端可以请求后端执行特定任务并获取结果。这种通信方式类似于前端发起的远程过程调用(RPC)。

使用场景

  • 执行复杂逻辑��需要后端处理的数据计算、文件操作、数据库交互等。
  • 获取后端数据:例如,从数据库获取数据并在前端展示。
  • 安全性需求:通过命令调用,能够在 Tauri 的安全模型下细粒度地控制权限。

实现步骤

  1. 在 Rust 后端定义命令

    使用 #[tauri::command] 宏定义一个可供前端调用的函数。

    src-tauri/src/lib.rs
    #[tauri::command]
    fn my_custom_command() {
    println!("我被 JavaScript 调用了!");
    }

    fn main() {
    tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![my_custom_command])
    .run(tauri::generate_context!())
    .expect("运行 Tauri 应用时出错");
    }

    :::note命令名称必须唯一。:::

    :::note由于胶水代码生成的限制,在 lib.rs 文件中定义的命令不能标记为 pub。如果将其标记为公共函数,您将看到如下错误:

    error[E0255]: the name `__cmd__command_name` is defined multiple times
    --> src/lib.rs:28:8
    |
    27 | #[tauri::command]
    | ----------------- previous definition of the macro `__cmd__command_name` here
    28 | pub fn x() {}
    | ^ `__cmd__command_name` reimported here
    |
    = note: `__cmd__command_name` must be defined only once in the macro namespace of this module

    :::

  2. 在前端调用命令

    使用 @tauri-apps/api 提供的 invoke 方法调用后端命令。

    前端 JavaScript 代码示例(如 React 组件)
    import { invoke } from '@tauri-apps/api/core';

    async function greetUser() {
    try {
    const greeting = await invoke('my_custom_command');
    console.log(greeting); // 输出: "我被 JavaScript 调用了!"
    } catch (error) {
    console.error('调用命令时出错:', error);
    }
    }

    // 在适当的生命周期钩子中调用 greetUser
  3. 配置权限

    tauri.conf.json 中,通过 CapabilitiesPermissions 配置命令的访问权限,确保命令的安全调用。

    tauri.conf.json 示例
    {
    "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/schema.json",
    "package": {
    "productName": "Pomodoro Timer",
    "version": "0.1.0"
    },
    "tauri": {
    "windows": [
    {
    "label": "main",
    "title": "ToDo Pomodoro",
    "width": 800,
    "height": 600,
    "resizable": true,
    "fullscreen": false,
    "decorations": true,
    "transparent": false,
    "alwaysOnTop": false,
    "visible": true,
    "url": "http://localhost:3000",
    "webviewAttributes": {
    "webPreferences": {
    "nodeIntegration": false
    }
    }
    }
    ],
    "security": {
    "capabilities": [
    {
    "identifier": "greet-capability",
    "description": "Allows the main window to greet users.",
    "windows": ["main"],
    "permissions": ["core:default"]
    }
    ]
    },
    "bundle": {
    "active": true,
    "targets": "all",
    "identifier": "com.yuxuetr.pomodoro",
    "icon": [
    "icons/32x32.png",
    "icons/128x128.png",
    "icons/128x128@2x.png",
    "icons/icon.icns",
    "icons/icon.ico"
    ]
    }
    }
    }

Events(事件)

Events 是 Tauri 中实现后端向前端推送消息的机制。与 Commands 不同,Events 是单向的,适用于需要实时通知前端的场景。

使用场景

  • 状态更新通知:后端状态变化时通知前端
  • 长时间任务进度:报告后台任务的执行进度
  • 系统事件通知:如系统状态变化、文件变动等

实现步骤

  1. 在 Rust 后端发送事件

    src-tauri/src/lib.rs
    use tauri::Manager;

    #[tauri::command]
    async fn start_process(window: tauri::Window) {
    // 模拟一个耗时操作
    for i in 0..100 {
    window.emit("process-progress", i).unwrap();
    std::thread::sleep(std::time::Duration::from_millis(100));
    }
    }
  2. 在前端监听事件

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

    // 监听进度事件
    await listen('process-progress', (event) => {
    console.log('Progress:', event.payload);
    });

Channels(通道)

Channels 提供了一种双向的、持久的通信通道,特别适合需要持续数据交换的场景。

使用场景

  • 流式数据传输:如实时日志、数据流
  • 长连接通信:需要保持持续通信的场景
  • 复杂的双向数据交换:需要前后端频繁交互的功能

实现示例

  1. 在 Rust 后端创建通道

    src-tauri/src/lib.rs
    use tauri::plugin::{Builder, TauriPlugin};
    use tauri::{Runtime, State, Window};
    use std::collections::HashMap;
    use std::sync::{Mutex, mpsc};

    #[derive(Default)]
    struct ChannelState(Mutex<HashMap<String, mpsc::Sender<String>>>);

    #[tauri::command]
    async fn create_channel(
    channel_id: String,
    state: State<'_, ChannelState>,
    window: Window,
    ) -> Result<(), String> {
    let (tx, mut rx) = mpsc::channel(32);
    state.0.lock().unwrap().insert(channel_id.clone(), tx);

    tauri::async_runtime::spawn(async move {
    while let Some(message) = rx.recv().await {
    window
    .emit(&format!("channel:{}", channel_id), message)
    .unwrap();
    }
    });

    Ok(())
    }
  2. 在前端使用通道

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

    // 创建并使用通道
    async function setupChannel() {
    const channelId = 'my-channel';
    await invoke('create_channel', { channelId });

    await listen(`channel:${channelId}`, (event) => {
    console.log('Received:', event.payload);
    });
    }

在 Rust 中执行 JavaScript

Tauri 还支持从 Rust 后端直接执行 JavaScript 代码,这提供了另一种前后端交互的方式。

实现示例

src-tauri/src/lib.rs
#[tauri::command]
async fn execute_js(window: tauri::Window) -> Result<String, String> {
// 执行 JavaScript 代码
window
.eval("console.log('从 Rust 执行的 JavaScript')")
.map_err(|e| e.to_string())?;

// 执行带返回值的 JavaScript
let result = window
.eval("(() => { return 'Hello from JS'; })()")
.map_err(|e| e.to_string())?;

Ok(result)
}

Commands、Events 与 Channels 的对比

特性Commands(命令)Events(事件)Channels(通道)
调用方向前端 → 后��后端 → 前端双向
响应类型同步/异步异步异步
使用场景一次性请求响应状态通知持续数据交换
数据流单次请求单次响应单向推送双向持续
适用性通用操作状态更新流式传输

示例代码

Commands 示例

完整的文件操作示例:

src-tauri/src/main.rs
use std::fs;
use tauri::command;

#[command]
async fn read_file(path: String) -> Result<String, String> {
fs::read_to_string(path)
.map_err(|e| e.to_string())
}

#[command]
async fn write_file(path: String, contents: String) -> Result<(), String> {
fs::write(path, contents)
.map_err(|e| e.to_string())
}

fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![read_file, write_file])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
// 前端调用示例
import { invoke } from '@tauri-apps/api/tauri';

async function handleFileOperations() {
try {
// 写入文件
await invoke('write_file', {
path: 'test.txt',
contents: 'Hello, Tauri!',
});

// 读取文件
const content = await invoke('read_file', {
path: 'test.txt',
});
console.log('File content:', content);
} catch (error) {
console.error('File operation failed:', error);
}
}

Events 示例

文件监控示例:

src-tauri/src/main.rs
use notify::{Watcher, RecursiveMode, watcher};
use tauri::Manager;
use std::time::Duration;

#[tauri::command]
async fn watch_directory(window: tauri::Window, path: String) -> Result<(), String> {
let (tx, rx) = std::sync::mpsc::channel();

let mut watcher = watcher(tx, Duration::from_secs(2)).map_err(|e| e.to_string())?;

watcher.watch(&path, RecursiveMode::Recursive).map_err(|e| e.to_string())?;

tauri::async_runtime::spawn(async move {
for res in rx {
match res {
Ok(event) => {
window.emit("file-change", event).unwrap();
}
Err(e) => println!("watch error: {:?}", e),
}
}
});

Ok(())
}
// 前端监听示例
import { listen } from '@tauri-apps/api/event';
import { invoke } from '@tauri-apps/api/tauri';

async function setupFileWatcher() {
// 启动文件监控
await invoke('watch_directory', {
path: './watched_folder',
});

// 监听文件变化事件
await listen('file-change', (event) => {
console.log('File changed:', event.payload);
});
}

Channels 示例

实时日志流示例:

src-tauri/src/main.rs
use tokio::sync::mpsc;
use std::collections::HashMap;
use std::sync::Mutex;

struct LogChannel(Mutex<HashMap<String, mpsc::Sender<String>>>);

#[tauri::command]
async fn start_log_stream(
channel_id: String,
state: tauri::State<'_, LogChannel>,
window: tauri::Window,
) -> Result<(), String> {
let (tx, mut rx) = mpsc::channel(100);
state.0.lock().unwrap().insert(channel_id.clone(), tx);

tauri::async_runtime::spawn(async move {
while let Some(log) = rx.recv().await {
window
.emit(&format!("log:{}", channel_id), log)
.unwrap();
}
});

Ok(())
}
// 前端实现
import { listen } from '@tauri-apps/api/event';
import { invoke } from '@tauri-apps/api/tauri';

async function setupLogStream() {
const channelId = 'app-logs';

// 创建日志流通道
await invoke('start_log_stream', { channelId });

// 监听日志消息
await listen(`log:${channelId}`, (event) => {
console.log('New log:', event.payload);
});
}

权限配置示例

{
"tauri": {
"security": {
"capabilities": [
{
"identifier": "file-access",
"description": "允许读写文件",
"windows": ["main"],
"permissions": ["fs:default"]
},
{
"identifier": "log-stream",
"description": "允许访问日志流",
"windows": ["main"],
"permissions": ["event:default"]
}
]
}
}
}

错误处理

src-tauri/src/lib.rs
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid input: {0}")]
InvalidInput(String),
}

impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}

#[tauri::command]
async fn handle_with_error() -> Result<String, Error> {
// 业务逻辑
Ok("Success".to_string())
}
// 前端错误处理
import { invoke } from '@tauri-apps/api/tauri';

try {
await invoke('handle_with_error');
} catch (error) {
console.error('Operation failed:', error);
}

最佳实践与安全性

  1. 权限控制

    • 始终使用最小权限原则
    • 明确定义每个命令的权限需求
    • 使用 allowlist 限制可用 API
  2. 数据验证

    • 在前后端都进行数据验证
    • 使用强类型定义接口
    • 处理所有可能的错误情况
  3. 性能优化

    • 使用适当的通信方式
    • 避免频繁的小数据传输
    • 合理使用异步操作

性能优化

  1. 批量处理

    • 合并多个小请求
    • 使用数据缓存
    • 实现请求队列
  2. 数据压缩

    • 大数据传输时使用压缩
    • 选择适当的序列化格式
  3. 异步处理

    • 使用异步命令
    • 实现后台任务
    • 合理使用线程池

实际案例

  1. 文件管理器

    • 使用 Commands 处理文件操作
    • 使用 Events 监控文件变化
    • 使用 Channels 传输大文件
  2. 实时聊天应用

    • 使用 Channels 处理消息流
    • 使用 Events 处理状态更新
    • 使用 Commands 处理用户操作

总结

Tauri 提供了丰富的前后端通信机制,每种方式都有其特定的使用场景:

  • Commands 适合一次性的请求-响应模式
  • Events 适合单向的状态通知
  • Channels 适合持续的双向数据交换

选择合适的通信方式对应用的性能和用户体验至关重要。同时,始终要注意安全性,合理使用权限控制和数据验证。

参考资源

鱼雪

这两天想用待办事项的番茄钟,以前也用过很多其他的产品,包括免费的、付费的,在手机上的还有在电脑上的都有。

然后最近都一直在学Rust的内容,以及之前学过一点Tauri,所以就想着自己写一个番茄钟的应用,然后就有了这个项目。

项目初衷

  1. 用Rust写一个待办事项番茄钟的应用,练习Rust的开发
  2. 足够简单好用,只专注于今天的事情, 不要有太多的功能(以往用的番茄钟都有很多功能,比如统计、报表等等,但是我只想专注于今天的事情, 比如四象限等还要想怎么安排,然后就容易导致事情拖延,托着拖着就不做了)
  3. 既有待办事项,又有番茄钟,两者结合,不要分开,这样就不用来回切换了
  4. 只专注于电脑端,不要有手机端,因为手机端的话,就容易分心,不专注于今天的事情了
  5. 只专注于电脑端,只专注于办公

项目地址

Github Repo: https://github.com/yuxuetr/todo-pomodoro

安装依赖

  1. 安装Rust
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
  1. 安装Node.js 安装链接和方法

  2. 安装pnpm

npm i -g pnpm

构建方式

  1. 克隆仓库
git clone https://github.com/yuxuetr/todo-pomodoro.git
  1. 安装依赖
cd todo-pomodoro
pnpm install
  1. 构建运行项目
pnpm run tauri dev
  1. 运行结果如图 待办事项番茄钟

设置应用的图标

图标文件存放在src-tauri/icons下,在这下面有针对不同平台的应用图标格式。

图标的设置在tauri.conf.json文件中,如下所示

"bundle": {
"active": true,
"targets": "all",
"identifier": "com.yuxuetr.dev",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}

在MacOS下,应用的图标是icon.icns,所以需要将图标文件放到icons目录下,然后在tauri.conf.json文件中设置图标的路径。

MacOS平台应用的图标大小是1024x1024,所以需要将图标文件转换成1024x1024的大小,然后修改成icon.icns放到icons目录下。

如果需要将图标由直角转换成圆角,可以使用在线工具。也可以试试我写的工具。

有三个不同的版本:

应用发布

第一次发布应用,需要先构建应用需要使用--target参数,指定目标平台

cargo tauri build --target aarch64-apple-darwin
# 或者
pnpm tauri build --target aarch64-apple-darwin

之后每次发布应用,只需要执行下面的命令即可

pnpm tauri build

应用构建与发布

执行命令后,会弹出下面的窗口

应用安装

然后按照Mac应用的方式安装应用,将应用拖到应用文件夹即可

项目后续

  1. 项目后期增加统计功能(如果有必要的话)
  2. 项目后期增加命令行功能(Tauri支持clip命令,可以在命令行中使用)
鱼雪

Tauri是Electron的有利竞争对手,Tauri使用Rust作为后端开发可以适配任意前端框架。 详细介绍可以访问Tauri官网。本文我们使用React作为前端开发框架, 实现一个简单案例,演示在Tauri中如何配置数据库访问。

本次实验的软件版本如下

  • Rust: 1.77.0
  • Node: v20.9.0
  • Vite: 5.0.0
  • pnpm: 8.15.6
  • React: 18.2.0
  • Tauri-plugin-sql: v1

创建项目

首先,我们先创建项目,创建项目有很多方式:

  • 可以使用Rust的包管理工具cargo
  • 或者使用Node.js的包管理工具npmyarnpnpm
  • 或者也可以使用Shell或Windows的PowerShell使用脚本创建
  • 也可以使用Bun的包管理工具bunx

但在创建项目之前,我们首先要安装Rust的编译器,因为Tauri的后端代码以及整个项目要使用 Rust编译器进行编译。虽然不一定需要编写Rust代码,但是一定需要Rust的编译器编译整个项目。

  1. Linux或MacOS操作系统安装方式如下:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  1. Windows操作系统可以直接下载rustup-init可执行文件,参考, 寻找对应平台的软件下载链接。

在本文中由于我们使用React作为Tauri的前端开发框架,所以我们使用Node.js的方式创建项目。 对比npm,yarn,pnpmpnpm会表现的更好,所以我们采用pnpm来创建我们的示例项目。

这里如果没有安装Node.js,可以参考,先下载后安装。

Node安装成功后,自带npm,如要要安装pnpm,使用以下命令:

npm i -g pnpm

创建Tauri项目命令如下:

npm create tauri-app
# 或
pnpm create tauri-app

创建命令执行后,首先需要输入项目工程名,然后根据提示选择自己喜欢的选项即可。

项目创建成功后目录如下:

$ tree tauri-sql-demo
tauri-sql-demo
├── README.md
├── index.html
├── package.json
├── public
│   ├── tauri.svg
│   └── vite.svg
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── assets
│   │   └── react.svg
│   ├── main.tsx
│   ├── styles.css
│   └── vite-env.d.ts
├── src-tauri
│   ├── Cargo.toml
│   ├── build.rs
│   ├── icons
│   │   ├── 128x128.png
│   │   ├── 128x128@2x.png
│   │   ├── 32x32.png
│   │   ├── Square107x107Logo.png
│   │   ├── Square142x142Logo.png
│   │   ├── Square150x150Logo.png
│   │   ├── Square284x284Logo.png
│   │   ├── Square30x30Logo.png
│   │   ├── Square310x310Logo.png
│   │   ├── Square44x44Logo.png
│   │   ├── Square71x71Logo.png
│   │   ├── Square89x89Logo.png
│   │   ├── StoreLogo.png
│   │   ├── icon.icns
│   │   ├── icon.ico
│   │   └── icon.png
│   ├── src
│   │   └── main.rs
│   └── tauri.conf.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

其中:

  • src是我们的前端代码目录,即跟我们平时使用的React代码目录相同,使用tauri-app创建方式, 并且使用React的前端框架,会默认使用Vite来构建前端代码。
  • src-tauri: 是Tauri的后端代码目录,是Rust项目工程组织代码,使用的是cargo做项目管理
  • src-tauri/tauri-config.json: 是用来配置前后端的协作,通信,后端API开放等功能

总而言之,相比于React项目,使用React的Tauri项目比纯React项目多了个src-tauri目录,其余内容就是一个 完整的React项目。

构建和运行初始化项目

初始化完项目,安装完依赖,我们先构建运行一下初始化项目,这样可以检查环境是否正常。

具体操作步骤如下:

  1. 进入到项目根目录
  2. 安装依赖
  3. 使用tauri-cli构建项目

命令如下:

cd tauri-sql-demo
pnpm install
pnpm tauri dev

运行成功后如下图: Tauri初始化界面

安装tauri-plugin-sql插件

初始化项目运行成功后,来开始我们的重头戏,配置Tauri的数据库访问。

这里首先要说明一点,在Tauri官网中默认配置tauri-plugin-sql是用的2.0的beta版本, 我们使用tauri-app创建的项目使用的是Tauri 1.x版本。所以我们在安装插件的时候需要指定v1版本。

配置tauri-plugin-sql分为两步:

  1. 安装核心插件,在Cargo.toml中添加插件配置
src-tauri/Cargo.toml
[dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v1"
features = ["sqlite"] # or "postgres", or "mysql"

其中:

  • git: 指定了使用Github的方式安装插件
  • branch: 指定软件版本,这里我们使用v1
  • features: 在Rust中features类似条件编译,我们选择sqlite则指定了我们是使用了sqlite数据库的插件
  1. 安装JavaScript客户端绑定
pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v1
# or
npm add https://github.com/tauri-apps/tauri-plugin-sql#v1
# or
yarn add https://github.com/tauri-apps/tauri-plugin-sql#v1

安装JavaScript 客户端API,使用JS的方式访问tauri-plugin-sql插件中功能,便于与我们的前端项目 结合。

配置tauri-plugin-sql插件

  1. 注册tauri-plugin-sql插件
src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_sql::Builder::default().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

这里,在Rust的main函数中,使用plugin方法注册tauri-plugin-sql插件

使用JavaScript或TypeScript访问数据库

我们使用一个单独的文件封装数据库的连接,数据库的增删改查。

代码如下:

src/dbop.ts
import Database from "tauri-plugin-sql-api";


// 初始化数据库连接
async function initDb() {
// sqlite数据库,路径相对于tauri::api::path::BaseDirectory::App
const db = await Database.load(
"sqlite:example.db"
);
return db;
}

// 创建表
export async function createAuthTable() {
const db = await initDb();
await db.execute(`
CREATE TABLE IF NOT EXISTS auth (
id INTEGER PRIMARY KEY AUTOINCREMENT,
userId TEXT NOT NULL,
scope TEXT NOT NULL
)
`);
}

// 插入数据
export async function insertAuth(userId: string, scope: string) {
const db = await initDb();
await db.execute(`
INSERT INTO auth (userId, scope) VALUES (?, ?)
`, [userId, scope]);
}

// 查询数据
export async function queryAuth() {
const db = await initDb();
return await db.select("SELECT * FROM auth");
}

// 更新数据
export async function updateAuth(id: number, userId: string, scope: string) {
const db = await initDb();
await db.execute(`
UPDATE auth SET userId = ?, scope = ? WHERE id = ?
`, [userId, scope, id]);
}

// 删除数据
export async function deleteAuth(id: number) {
const db = await initDb();
await db.execute(`
DELETE FROM auth WHERE id = ?
`, [id]);
}

首先,我们从tauri-plugin-sql-api中导入Database对象, 关于数据库的操作我们都要依赖这个Database对象

由于tauri-plugin-sql都是支持异步并发操作,所以我们创建的函数都是异步函数, 函数分别是:

  • initDb: 创建数据库连接,这里我们指定SQLite的文件名为example.db,返回创建成功后的数据库db实例
  • createAuthTable: 创建Auth数据库表
  • insertAuth: 插入数据,接收两个参数
  • queryAuth: 查询Auth表数据
  • updateAuth: 更新Auth表数据,接收三个参数
  • deleteAuth: 删除Auth表数据,接收id参数

配置Tauri文件访问权限

在本案例中,我们使用SQLite数据库,tauri-plugin-sql插件,底层是依赖sqlx库来操作数据库。 在连接SQLite数据库时,如果example.db数据库文件不存在,sqlx则会自动创建example.db文件, 那么就需要有文件访问功能开启,否则不能正确创建example.db文件,会导致数据库不能正确创建,导致最终 案例失败。如果这里使用的是MySQL或者Postgres则不需要配置这里。

具体操作如下,我们需要在src-tauri/tauri.config.json中开启fs权限

src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devPath": "http://localhost:1420",
"distDir": "../dist"
},
"package": {
"productName": "tauri-sql-demo",
"version": "0.0.0"
},
"tauri": {
"allowlist": {
"all": false,
"fs": {
"all": true
},
"shell": {
"all": false,
"open": true
}
},
"windows": [
{
"title": "tauri-sql-demo",
"width": 800,
"height": 600
}
],
"security": {
"csp": null
},
"bundle": {
"active": true,
"targets": "all",
"identifier": "com.tauri.dev",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
}

在前端中调用数据库操作

src/App.tsx
import { useState, useEffect } from "react";
import { createAuthTable, insertAuth, queryAuth } from './dbop';

function App() {
const [rows, setRows] = useState([]);
useEffect(() => {
async function setupDb() {
await createAuthTable();
await insertAuth('user123', 'admin');
const queriedRows = await queryAuth();
console.log(`Queried Rows Length: ${queriedRows.length}`);
setRows(queriedRows);
}

setupDb();
}, []);

return (
<div className='App'>
<h1>Tauri + React Database Example</h1>
<div>
<h2>Auth Table Rows</h2>
<h2>Queried Rows Length: {rows.length}</h2>
<ul>
{
rows.map((row, index) => (
<li key={index}>
ID: {row.id}, UserId: {row.userId}, Scope: {row.scope}
</li>
))
}
</ul>
</div>
</div>
)
}

export default App;

首先,我们导入我们的数据库操作; 然后使用useState存储数据库的查询结果,存放在rows变量中; 最后,遍历查询出来的的结果做展示,如下图:

tauri-plugin-sql连接数据库结果展示

案例地址

Tauri-SQL-Plugin-Demo

鱼雪