先说结论
这个仓库的重点,不是 Vue 页面,也不是 greet 函数,而是验证 Tauri 的前端、Rust 后端、Runtime、WebView 和 OpenHarmony Ability 能不能串起来。
最近我看了一个很有意思的仓库:richerfu/tauri-demo。
第一眼看,它像一个普通的 Tauri + Vue Demo。页面是默认模板,Rust 侧只有一个 greet command。
但如果只这么看,就把重点看偏了。
README 里写得很直接:这是一个 Tauri prototype for OpenHarmony/HarmonyNext。也就是说,它不是在教你写一个桌面应用,而是在验证一件事:
Tauri 这套应用模型,能不能被搬到 OpenHarmony / HarmonyNext 上?
这篇先不讲实操,先把这条链路讲清楚。

一、它不是一个普通的 Tauri Hello World
普通 Tauri 项目,大概是这样的结构:
txt
Web 前端
↓
Tauri JS API
↓
Rust command
↓
Tauri Runtime
↓
桌面系统 WebView / 窗口 / 原生能力
而这个仓库要验证的是另一条链路:
txt
Vue 前端
↓
Tauri JS API
↓
Rust command
↓
Tauri Runtime
↓
OpenHarmony Ability
↓
OHOS WebView / N-API / 原生动态库
所以你会发现,前端代码和 Rust 业务代码都很简单。
简单不是因为没写完,而是因为它要验证的不是业务复杂度,而是最小链路能不能打通。
我建议读这个仓库时,不要先盯着页面效果看,而是先看构建命令、Cargo.toml、生成出来的 OHOS 工程,以及 EntryAbility 如何接住 Rust 动态库。
二、前端层:Vue 只是入口,不是重点
从 package.json 看,项目使用的是 Vue 3、Tauri v2 API 和 Tauri opener 插件,开发侧是 Vite、TypeScript、Vue TSC 和 Tauri CLI。
前端入口 src/main.ts 非常干净,只做 Vue 挂载:
ts
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
真正的跨端调用发生在 App.vue。
它从 @tauri-apps/api/core 里导入 invoke,然后在表单提交时调用 Rust command:
ts
async function greet() {
greetMsg.value = await invoke("greet", { name: name.value });
}
这行代码很小,但意义很大。
它代表 WebView 里的前端页面,通过 Tauri 的 IPC 通道,去调用 Rust 侧的本地函数。
在普通桌面环境里,这说明 Tauri 的前后端通信打通了。
在 OpenHarmony 场景里,它还多了一层意义:这个调用链要能穿过 OHOS 的应用模型继续成立。
三、Rust 层:最小 command,验证最大链路
Rust 侧的代码也很克制。
src-tauri/src/lib.rs 里定义了一个 greet command:
rust
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
然后在 run() 里注册进去:
rust
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
这里有两个关键点。
第一,#[tauri::command] 让 Rust 函数可以被前端调用。
第二,generate_handler![greet] 把这个 command 注册给 Tauri。
所以完整调用链是:
txt
Vue 表单
↓
invoke("greet")
↓
Tauri IPC
↓
generate_handler![greet]
↓
Rust greet()
↓
返回字符串给前端
这就是 Tauri 的最小闭环。
四、真正的地图在 Cargo.toml
如果只看 Vue 和 greet,这个项目看不出什么特别。
真正关键的是 src-tauri/Cargo.toml。
这里的 tauri 和 tauri-build 不是普通 crates.io 版本,而是指向 richerfu/tauri 的 feat/open-harmony 分支。
同时,项目还 patch 了 Wry、Tao、tauri-runtime、tauri-utils 等关键组件,并引入了 OpenHarmony Ability 相关依赖。
txt
tauri
tauri-build
tauri-runtime
tauri-runtime-wry
wry
tao
openharmony-ability
napi-ohos
这说明一件事:
这个 demo 的核心工作,不在业务代码,而在 Tauri runtime、窗口层、WebView 层和 OHOS Ability 桥接层。
也就是说,这不是"写一个鸿蒙页面",而是"让 Tauri 的应用模型被 OHOS 承载"。
五、构建结果不是桌面 App,而是 OHOS 工程
README 里的构建方式是:
bash
cd src-tauri && cargo tauri ohos build
构建后,要用 DevEco Studio 打开:
txt
src-tauri/gen/ohos
这一步很关键。它说明 Tauri CLI 在这里的角色,不只是"打一个桌面包",而是生成一个可以被 OHOS 工具链继续处理的工程。
生成的 OHOS 工程里,module.json5 定义了 EntryAbility,设备类型包含 phone、tablet、2in1,并申请了 INTERNET 权限。

六、EntryAbility 是 Tauri 和 OHOS 的接头
再看 EntryAbility.ets。
它继承自 @ohos-rs/ability 的 NativeAbility,并声明了一个很重要的字段:
ts
public moduleName: string = "tauri_demo_lib"
这个名字正好对应 Rust 侧的动态库名称。
换句话说,OHOS 的 Ability 启动后,会通过这层 NativeAbility,把生命周期和 Rust / Tauri 侧的入口接起来。
README 里也特别备注了一句:
RustAbility will forward lifecycle automatically.
我的理解是,这句话才是整个 demo 的关键:OHOS 的生命周期,需要被转发给 Rust/Tauri runtime,Tauri 才能继续完成初始化、窗口创建、WebView 承载和事件处理。
七、一张图总结
把它完整串起来,就是下面这条链路:
txt
Vue 页面
↓
@tauri-apps/api/core invoke()
↓
Tauri IPC
↓
Rust #[tauri::command]
↓
Tauri Builder / Runtime
↓
richerfu/tauri feat/open-harmony
↓
Wry / Tao OpenHarmony 适配
↓
src-tauri/gen/ohos
↓
EntryAbility / NativeAbility
↓
OHOS WebView / 原生动态库

所以这个项目虽然小,但它的价值很清楚:
tauri-demo 不是一个业务 demo,而是一个 Tauri OpenHarmony 适配链路的最小验证工程。
八、它证明了什么?还没证明什么?
它已经证明了几个关键点:
- Tauri CLI 可以走到 OHOS 构建路径。
- Vue 前端可以通过 Tauri
invoke调 Rust。 - Rust 侧可以作为动态库被 OHOS Ability 承接。
- 生成的 OHOS 工程可以交给 DevEco Studio 继续运行。
但它还没有证明全部能力。
比如复杂插件、文件系统、窗口管理、多页面、系统权限、打包发布、生产级调试,这些都还需要后续继续验证。
所以这篇文章的结论很简单:
这个 demo 值得看,不是因为它写了多少代码,而是因为它把 Tauri 上鸿蒙的关键路径暴露出来了。
下一篇,我们不再讲原理,直接动手跑一遍:安装依赖、构建 OHOS 工程、用 DevEco Studio 打开,并尝试改一个 Rust command。