Talk is cheap. Show me your code

Rust + Tauri 开发一个自动生成申论的桌面应用

前端开发桌面应用,第一反应肯定是 Electron

但 Electron 有一个众所周知的问题:每一个应用都会打包一个 chromium。如果电脑上安装了10个 Electron 应用,就会安装10个 chromium

而 Tauri 使用 WebView 作为 GUI 方案,不会打包在应用内,而是检查系统是否有预装 WebView,从而避免多个应用重复安装的问题。

 

一、创建项目

Tauri 使用了 Rust,所以需要提前安装 Rust 的相关环境,可以参考《Rust 走马观花(一)—— 从安装到编译》或者官方文档《预先准备》

Tauri 桌面应用由前端应用和后端应用组成,前端应用可以是任意一个 web 项目,本文将使用 vite + react + ts 构建

yarn create vite my-tauri-app --template react-ts

然后安装 tarui-cli,并创建 Rust 项目

cargo install tauri-cli
cargo tauri init

安装完成后会在原本的目录中新增一个 src-tauri 目录,这就是 tauri 生成的 rust 应用,也就是我们桌面应用的后端部分

安装过程会有一些配置项,可以参考截图输入。即使输错了也没问题,创建项目后可以在 tauri.conf.json 中修改配置

注意:这里的 devPath 必须为有效地址,否则无法正确启动开发模式

到此为止,一个 Tarui 项目的基本结构就已经搭建好了,可以使用 cargo tauri dev 命令运行项目

开发完成后,可以通过 cargo tauri build 命令构建,不过在构建之前,需要修改 tauri.conf.json 中的 identifier 字段,也就是当前应用的 id,需要保证唯一性

如需构建 windows 应用,还得在配置文件中添加 wix 配置项

{
  "tauri": {
    "bundle": {
     "identifier": "com.tauri.xxxxxxxx", // 保证唯一
      "windows": {
        "wix": {
          "language": "zh-CN"
        }
      }
    }
  }
}

 

二、功能开发(JS版本)

接下来完成应用的业务功能,也就是一键生成一篇申论

具体功能是模仿申论生成器,源码来自 GitHub: https://github.com/Uahh/slscq

过程就不再赘述,可以按照 web 应用的形式开发,然后打包为桌面应用。也就是仅用 Tauri 做一个桌面应用的壳

 


 这时候应用的图标还是 Tauri 的默认图标,可以先设计一个自己的图标 (1024 x 1024px, png, 透明背景),然后重命名为 app-icon.png,放到 src-tauri 目录下

然后在 src-tauri 目录下启动终端,执行命令 cargo tauri icon,tauri 就会在 icons 目录下自动生成一套图标

最后在 tauri.conf.json 修改应用标题(如果创建项目的时候已配置好则忽略这一步)

这样一个相对完整的桌面应用的就开发完成

但就像上文所说,这样的应用还只是一个套壳的 web 应用,没有用到桌面应用的特性,比如文件读写,也没用到 Rust,接下来就将逐步完善

 

三、文件导出

文章生产之后,顺利成章的就会有“导出”的需求。可以通过文件系统 fs 来实现该功能

文件系统的读写功能默认是关闭的,需要在配置文件 tauri.conf.json 中的 allowlist 开启

{
  "tauri": {
    "allowlist": {
      "fs": {
        "scope": ["*"],
        "all": true
      }
    }
  }
}

这里最关键的是 scope 字段(必填),用于限制应用可访问的本地文件目录。我这里设置为了通配符,需要根据实际需求调整

保存文件的时候需要文件路径,常见的交互是弹出 dialog 让用户选择文件的保存历经,这就需要用到 dialog 组件,所以最终的 allowlist 为:

{
  "tauri": {
    "allowlist": {
      "dialog": {
        "all": true
      },
      "fs": {
        "scope": ["*"],
        "all": true
      }
    }
  }
}

fs 和 dialog 的能力是 Rust 提供的,在前端应用使用 Rust 还需要引入另外的依赖包 @tauri-apps/api

yarn add @tauri-apps/api

最终下载文件的完整逻辑为

import { save } from '@tauri-apps/api/dialog';
import { writeTextFile } from '@tauri-apps/api/fs';

const [content, setContent] = useState<{
  title: string;
  plaintext: string;
  html: string;
}>();

const handleDownload = async () => {
  if (!content) return;
  const filePath = await save({
    defaultPath: `${content.title}.txt`,
  });
  if (!filePath) return;
  writeTextFile(filePath, content.plaintext);
}

 

四、使用 Rust 改造

目前应用的核心逻辑还是用 js 实现的,接下来可以改造为 rust,毕竟 rust 的性能更好

改造的过程不多展开,假如最终在 main.rs 中实现了一个函数 generator, 直接返回完整内容

该函数需要以指令的形式暴露给前端应用,所以需要加上 #[tauri::command] 的宏

最终还需要在 main 函数中通过 invoke_handler 暴露该指令

.invoke_handler(tauri::generate_handler![ fn1, fn2, fn3 ])

然后在前端应用中,通过 tauri 提供的 invoke 方法使用指令

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

const handleSubmit = async () =>const res = await invoke<string>('generator', { 
    // 对应 rust 函数中定义的参数名
    theme: '文章主题',
    size: 100, 
  });
  console.log('handleSubmit===>', res);
}

调用的时候需要注意以下几点:

1. invoke 是一个异步函数,返回 Promise

2. invoke 的第一个参数是 rust 函数名,第二个参数是一个对象,需要按照 rust 中定义的参数名传参 

 

五、跨平台编译

本小节内容参考自官网《跨平台编译》

Tauri 的编译十分依赖本地环境,所以无法在本地实现跨平台编译,更好的方案是使用 GitHub Actions

首先需要创建一个 GitHub 仓库,然后创建一个工作流

 

可以使用 Tauri 提供的工作流示例,该脚本会在推送满足条件的 tags 时执行

工作流开始运行之后,可以在 Actions 中查看进度

工作流执行完成后,会创建一个草稿状态的 release,并携带构建产物

可以下载这些安装包,在各个环境验证一下。验证无误,可以编辑该 release 并发布

至此一个完整的 Tauri APP 构建流程就结束了~

 

posted @ 2023-08-02 11:07  Wise.Wrong  阅读(4499)  评论(0编辑  收藏  举报