用 Tauri 跨平台框架在鸿蒙 PC 上开发应用:从 Rust 后端到真机跑通的完整实践
用 Tauri 跨平台框架在鸿蒙 PC 上开发应用:从 Rust 后端到真机跑通的完整实践
欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
关键词:鸿蒙 PC,Tauri,跨平台框架,Rust,开源鸿蒙,ArkTS,ArkWeb,N-API,cdylib,HAP,Web 前端,IPC
一、前言
随着开源鸿蒙 PC(HarmonyOS PC)设备的落地,一个现实的问题摆在了 Web 与跨平台开发者面前:既有的前端技术栈和跨平台框架,能不能直接搬到这台新的桌面设备上?重复学习一套全新的 UI 体系成本太高,而用 Tauri 这类跨平台框架在鸿蒙 PC 上复用 Rust 后端与 Web 前端,是一条投入产出比很高的路径。
Tauri 是目前主流的跨平台框架之一:前端用 HTML/CSS/JS,后端用 Rust,两者通过 IPC 通信,产物体积小、内存占用低。虽然 Tauri 官方主版本尚未把 HarmonyOS 列为一级支持目标,但社区已经有可用的鸿蒙分支,配合 Rust 的 aarch64-unknown-linux-ohos 工具链,完全可以在鸿蒙 PC 上把一个 Tauri 应用从源码跑到真机窗口。
本文是我在这台鸿蒙 PC 上(HUAWEI MateBook Pro,HarmonyOS 7.0 / OpenHarmony 7.0 / API 26,aarch64)从零实践的完整记录:用 Tauri 的鸿蒙分支搭起 Rust 后端 + Web 前端的最小工程,实现"输入名字 → 调用 Rust → 返回问候语"的 IPC 闭环,并展示原生环境信息。文中的代码均在实际工程中验证过,配图全部来自真机截图,希望给想在鸿蒙 PC 上做跨平台开发的读者一条可复现的路线。
二、Tauri 在鸿蒙 PC 上是怎么跑起来的

在动手之前,先弄清楚架构,后面排错才有的放矢。Tauri 应用在鸿蒙 PC 上的运行形态可以概括为一句话:ArkTS 壳 + Rust 内核 + ArkWeb 窗口。
┌─────────────────────────────────────────┐
│ 鸿蒙 PC 应用进程 (HAP) │
│ │
│ ArkTS 入口 Ability │
│ └─ NativeAbility(N-API 宿主) │
│ └─ 加载 lib{app}_lib.so (Rust) │
│ └─ tauri + wry (ohos 后端) │
│ └─ ArkWeb webview │
│ └─ Web 前端 │
│ ▲ │
│ └── Tauri IPC ──┐ │
│ invoke("greet", …) │ │
└──────────────────────────────┴──────────┘
三个关键角色:
- ArkTS 壳:应用入口是一个普通的鸿蒙 Ability,但它继承的是
NativeAbility。这个基类由社区提供的 N-API 宿主库实现,作用是在 Ability 启动时把 Rust 编译出的动态库(lib{app}_lib.so)当作 N-API 模块加载进进程。 - Rust 内核:
tauri与wry(Tauri 的窗口/webview 库)都有 ohos 后端。wry起的是 ArkWeb(Chromium 内核)窗口,前端资源由 Tauri 的自定义资源协议提供。 - Tauri IPC:前端通过
window.__TAURI__.core.invoke直接调用 Rust 侧的#[tauri::command]函数,这条链路在鸿蒙 PC 上与桌面端完全一致——这也是选择 Tauri 这个跨平台框架最大的收益:既有代码几乎不用改。
理解了这个分层,就明白鸿蒙 PC 上的工程其实是两部分:Rust 侧负责编译出 cdylib 动态库,鸿蒙侧(src-tauri/gen/ohos)是一个标准的 hvigor 工程,负责打包 HAP 并在启动时加载它。
三、环境准备
我的实践环境如下,全部步骤均在真机上完成:
- 设备:HUAWEI MateBook Pro(HAD-W32),aarch64
- 系统:HarmonyOS 7.0.0.111 / OpenHarmony-7.0.0.109,API 26
- Rust 工具链:1.99.0,target
aarch64-unknown-linux-ohos(鸿蒙 PC 上可直接运行的本机宿主工具链) - 构建工具:hvigor + ohpm(来自 hmos-clt 命令行工具)
有两点环境上的特殊情况值得提前说明,都是鸿蒙 PC 与常规 Linux 桌面的差异:
- 签名问题:鸿蒙对可执行 ELF 有签名校验,未签名的二进制无法执行。因此 Rust 工具链下载后,需要对工具链里的 ELF 逐一自签名;Cargo 依赖的 OpenSSL 也需要预编译的 ohos 版本。我们把工具链统一放在工作区共享目录,通过环境变量注入。
- 无 bash:鸿蒙 PC 的终端是 POSIX sh 环境,工程内的自动化脚本要按 POSIX sh 编写,不要使用 bash 特有语法。
工具链定位采用"项目自检向上查找"的方式,构建脚本从项目目录向上逐级寻找共享工具链目录,这样多个 Tauri 鸿蒙 PC 项目可以共用同一份 Rust 工具链和 Cargo 缓存,避免每份工程都背上几百 MB 的环境副本。
四、Rust 侧:两个 IPC 命令
先看 Rust 侧的核心代码(src-tauri/src/lib.rs),一共两个 Tauri 命令:
use serde::Serialize;
#[derive(Serialize)]
struct AppInfo {
product: &'static str,
version: &'static str,
os: &'static str,
arch: &'static str,
family: &'static str,
ohos: bool,
ohos_library: Option<&'static str>,
ohos_package: Option<&'static str>,
}
#[tauri::command]
fn app_info() -> AppInfo {
AppInfo {
product: env!("CARGO_PKG_NAME"),
version: env!("CARGO_PKG_VERSION"),
os: std::env::consts::OS,
arch: std::env::consts::ARCH,
family: std::env::consts::FAMILY,
ohos: cfg!(target_env = "ohos"),
ohos_library: option_env!("WRY_OHOS_LIBRARY"),
ohos_package: option_env!("WRY_OHOS_PACKAGE"),
}
}
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {name}! You've been greeted from Rust!")
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![app_info, greet])
.run(tauri::generate_context!())
.expect("error while running Aurora");
}
说明几个要点:
greet是最简 IPC 示例:前端传name,Rust 返回拼接的问候语。参数名从前端的驼峰name自动映射,无需手动转换。app_info用于验证运行环境。cfg!(target_env = "ohos")在 ohos 目标下编译为true;WRY_OHOS_LIBRARY/WRY_OHOS_PACKAGE是 wry 的 ohos 后端在编译期注入的环境变量,分别对应动态库名与鸿蒙包名。这个命令返回的 JSON(见文末真机截图)能一眼确认"Rust 确实跑在鸿蒙目标上"。#[cfg_attr(mobile, tauri::mobile_entry_point)]是关键注解:在 ohos 目标下(归入 mobile 侧),入口不再是main,而是由 N-API 宿主调用的移动入口,run()由NativeAbility在 Ability 启动时触发。
Cargo.toml 中与鸿蒙相关的核心配置:
[package]
name = "aurora"
version = "0.1.0"
edition = "2021"
[lib]
name = "aurora_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2.8", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
crate-type 必须包含 cdylib——这正是鸿蒙侧要加载的那个动态库的来源。编译命令也很直接:
source tools/env.sh
cargo build --target aarch64-unknown-linux-ohos --release
其中 tools/env.sh 注入了 ohos 目标的链接器(指向项目内的 ohos-cc-sign 包装脚本,编译产物会自动完成签名)、CC/CXX/AR 以及 OpenSSL 路径。
五、前端:一份 Web 代码,两条运行路径
Tauri 的前端就是普通 Web 页面。本工程前端零依赖(没有 React/Vue,也没有打包器),tauri.conf.json 里 frontendDist 直接指向 web/ 目录:
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Aurora",
"identifier": "com.example.aurora",
"build": { "frontendDist": "../web" },
"app": {
"withGlobalTauri": true,
"windows": [
{ "label": "main", "url": "index.html", "width": 1120, "height": 760 }
]
}
}
withGlobalTauri: true 会在前端注入全局 window.__TAURI__,不需要 npm 安装任何 Tauri 包。前端调用 Rust 的代码如下(web/main.js 摘录):
const invoke = window.__TAURI__?.core?.invoke;
const hasNativeRuntime = typeof invoke === "function";
greetForm.addEventListener("submit", async (event) => {
event.preventDefault();
const name = nameInput.value.trim() || "鸿蒙开发者";
showResponse("idle", "CALLING RUST", "正在通过 Tauri IPC 调用 Rust…");
try {
const message = hasNativeRuntime
? await invoke("greet", { name })
: `Hello, ${name}! 当前为浏览器预览,请在鸿蒙应用中体验 Rust 调用。`;
showResponse(
hasNativeRuntime ? "success" : "idle",
hasNativeRuntime ? "RUST IPC SUCCEEDED" : "BROWSER PREVIEW",
message
);
} catch (error) {
showResponse("error", "RUST IPC FAILED", String(error));
}
});
这里做了一个对开发体验很有用的设计:同一份前端在两个环境里都能跑。有原生桥(invoke 存在)时走真实 IPC;直接用浏览器打开 web/index.html 时自动降级为"浏览器预览"模式,并在界面上明确标注。这样界面和交互可以在浏览器里快速迭代,需要验证 IPC 时再构建到鸿蒙 PC 上,不必每次都等完整的 HAP 构建链路。
六、鸿蒙侧工程与 HAP 构建
Rust 编译产物(libaurora_lib.so)需要进入鸿蒙工程才能打包。Tauri 的鸿蒙分支会在 src-tauri/gen/ohos 下生成一个标准 hvigor 工程,其入口 Ability 的关键部分是:
import { NativeAbility } from "@ohos-rs/ability";
export default class EntryAbility extends NativeAbility {
public moduleName: string = "aurora_lib";
// … onCreate 中触发 Rust 入口
}
moduleName 指向 Rust 产出的动态库名,NativeAbility 据此完成 N-API 模块的加载与启动。构建 HAP 的流程就是鸿蒙标准三步:
cd src-tauri/gen/ohos
ohpm install
hvigorw assembleHap --no-daemon
构建出的 HAP 用既有签名材料签名后即可安装运行。整个流程脚本化之后,从源码到真机窗口只需要 npm run build 一条命令。
两个容易踩的坑,提前给后来者排雷:
- 运行时配置不会自动进包:根目录
assets/下的文件不会被 hvigor 打进 HAP。tauri.conf.json这类运行时需要读取的配置,必须额外同步一份到entry/src/main/resources/rawfile/,否则应用运行时读不到配置。我们在工程测试里加了断言校验这份同步,防止以后改动时漏掉。 - SDK 版本号格式:hvigor 配置里的 SDK 版本必须写纯三段式(如
26.0.0),不能带括号后缀(如26.0.0(26)),否则构建直接报错。
七、真机运行效果
应用启动后是一个标准的鸿蒙 PC 窗口,界面左侧是说明区,右侧是交互卡片。初始状态如下:

在输入框中输入名字(默认"鸿蒙开发者"),点击"调用 Rust",前端通过 Tauri IPC 调用 Rust 侧的 greet 命令:

调用成功后,绿色状态卡片显示 RUST IPC SUCCEEDED 与 Rust 返回的问候语,证明 IPC 链路完整打通:

点击"应用信息"面板,app_info 命令返回的原生环境信息以 JSON 展示:
{
"product": "aurora",
"version": "0.1.0",
"os": "linux",
"arch": "aarch64",
"family": "unix",
"ohos": true,
"ohos_library": "aurora_lib",
"ohos_package": "com.example.aurora"
}
其中 ohos: true、ohos_library、ohos_package 三个字段由 ohos 目标编译期注入,os: "linux" 则是因为 OpenHarmony 的 ABI 归属于 linux 家族(aarch64-unknown-linux-ohos)——这正是 std::env::consts::OS 的如实输出,也侧面印证了 Rust 的 ohos target 与 Linux target 的亲缘关系。
八、为什么选择 Tauri 这条路线
在鸿蒙 PC 上做跨平台开发,目前可选的路径不止一条。把实践后的对比写在这里,供读者按自己的技术栈决策:
- 复用面:Tauri 的前端就是标准 Web,Rust 后端与桌面版共享同一套 crate 生态。已经在做 Tauri 桌面应用的团队,向鸿蒙 PC 迁移的增量成本主要在构建链路,而非业务代码。
- 产物形态:最终产物是标准 HAP,可正常走签名、安装、分发的鸿蒙 PC 流程;对系统而言它就是一个普通鸿蒙应用。
- 性能:界面渲染交给系统自带 ArkWeb,Rust 侧无 GC、常驻内存小,与 Tauri 在其他平台上"轻"的特点一致。
- 风险提示:鸿蒙分支(
feat/open-harmony)属于社区维护,尚未进入 Tauri 官方主线,API 稳定性与文档完备度不如桌面端,选型时需要评估锁定风险。
九、结语与下一步
本文验证的核心结论是:在鸿蒙 PC 上,用 Tauri 跨平台框架 + Rust + Web 前端的组合开发原生应用是完全可行的。Rust 以 cdylib 形式编译进 HAP,ArkTS 壳通过 N-API 加载它,ArkWeb 承载 Web 界面,IPC 链路与桌面端 Tauri 完全一致。
在此基础上,下一步自然是把这条链路用到真正的业务上:比如做一个基于 Tauri IPC 的便签/待办应用(Rust 侧负责 JSON 文件持久化),或者探索 Rust 生态里的原生能力(图像处理、网络请求)在鸿蒙 PC 上的封装。工具链层面,多项目共享工具链 + 脚手架生成新工程的布局也已经跑通,新项目从模板到可构建只需要一条命令。
如果你也在鸿蒙 PC 上尝试 Tauri 或其他跨平台框架,欢迎交流踩坑经验;
更多推荐




所有评论(0)