初识Tauri

前端技术日新月异,利用前端技术开发桌面应用程序是一个焦点话题,目前已有Electron这样的重量级框架,也诞生了Tauri这样的年轻充满朝气的框架。

本人更偏爱Tauri框架,本文结合一个小例子对该框架做简单介绍。

Tauri简介

一言以蔽之,Tauri和Electron一样,是一种利用Web技术开发跨平台桌面应用的框架。就当前市场占有率而言,Electron无疑是该领域的王者。

两者主要区别如下:

  • Electron软件打包自带完整浏览器内核,软件体积巨大;Tauri利用操作系统自带的WebView进行渲染,体积较小,但是对软件兼容性测试提出了更高要求。
  • Electron采用JS进行全栈开发(利用Nodejs进行后台开发);Tauri后台采用Rust,前台可以使用任意前端框架。
  • Electron生态更加成熟,且有大型软件已使用该技术栈;Tauri相对年轻,生态系统正在构建。

案例说明

本文在示例代码的基础上,添加一个按钮和段落,用户单击按钮时,会创建一个文件并向文件中写入文本。文件操作逻辑借助Rust后台实现。

创建项目很简单,执行以下代码即可:npm create tauri-app@latest

前台Vue代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">
import { ref } from "vue";
import { invoke } from "@tauri-apps/api/core";

const writtenBytes = ref(0);
async function create_file() {
writtenBytes.value=await invoke("create_file");
}
</script>

<template>
<main class="container">
<button @click="create_file">创建文件</button>
<p>{{ writtenBytes }}</p>
</main>
</template>
  • 在既有代码的基础上分别新建一个writtenBytes变量,并创建一个<button><p>标签,后者用于呈现该变量,给按钮单击事件绑定create_file处理逻辑。
  • 重点在于create_file的逻辑实现,在这里通过invoke方法调用rust代码中的create_file()方法,前台和后台的方法名一致。

后台Rust代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
use std::ptr;
use winapi::um::fileapi::{CreateFileW, WriteFile, CREATE_ALWAYS};
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::winnt::{FILE_ATTRIBUTE_NORMAL, GENERIC_WRITE};

#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}

#[tauri::command]
fn create_file() -> u32 {
let mut bytes_written = 0;
unsafe {
let file_name = "D:\\example.txt\0".encode_utf16().collect::<Vec<u16>>();
let file_handle = CreateFileW(
file_name.as_ptr(),
GENERIC_WRITE,
0,
ptr::null_mut(),
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
ptr::null_mut(),
);
if file_handle == INVALID_HANDLE_VALUE {
eprintln!("Failed to create file");
return 0;
}

let data = "Hello, world!我是李浩";
WriteFile(
file_handle,
data.as_ptr() as *const _,
data.len() as u32,
&mut bytes_written,
ptr::null_mut(),
);
CloseHandle(file_handle);
}
return bytes_written;
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet, create_file])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
  • Rust后台代码中的create_file()方法主要功能是创建一个文件,并向该文件写入内容。
  • 使用了名为winapi的包,实际上有微软官方包可用(windowswindows-sys),但这两个包无法调用WriteFile(),可能是Bug。
  • 定义函数后,需要在invoke_handler()参数中指定该方法,这样才能暴露给前台调用。

评论