用 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", …)   │          │
└──────────────────────────────┴──────────┘

三个关键角色:

  1. ArkTS 壳:应用入口是一个普通的鸿蒙 Ability,但它继承的是 NativeAbility。这个基类由社区提供的 N-API 宿主库实现,作用是在 Ability 启动时把 Rust 编译出的动态库(lib{app}_lib.so)当作 N-API 模块加载进进程。
  2. Rust 内核:tauri 与 wry(Tauri 的窗口/webview 库)都有 ohos 后端。wry 起的是 ArkWeb(Chromium 内核)窗口,前端资源由 Tauri 的自定义资源协议提供。
  3. 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 一条命令。

两个容易踩的坑,提前给后来者排雷:

  1. 运行时配置不会自动进包:根目录 assets/ 下的文件不会被 hvigor 打进 HAP。tauri.conf.json 这类运行时需要读取的配置,必须额外同步一份到 entry/src/main/resources/rawfile/,否则应用运行时读不到配置。我们在工程测试里加了断言校验这份同步,防止以后改动时漏掉。
  2. SDK 版本号格式:hvigor 配置里的 SDK 版本必须写纯三段式(如 26.0.0),不能带括号后缀(如 26.0.0(26)),否则构建直接报错。

七、真机运行效果

应用启动后是一个标准的鸿蒙 PC 窗口,界面左侧是说明区,右侧是交互卡片。初始状态如下:

真机截图:应用启动初始状态

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

真机截图:调用中状态

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

真机截图:Rust 调用成功

点击"应用信息"面板,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 或其他跨平台框架,欢迎交流踩坑经验;

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐