本文最后更新于97 天前,其中的信息可能已经过时,如有错误请发送邮件到3497198266@qq.com
Rust 是由 Mozilla 主导开发的高性能编译型编程语言,遵循”安全、并发、实用”的设计原则。Rust 速度惊人且内存利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成。
未来越来越多的系统将会使用Rust编写,所以我也决定以后使用Rust编写大部分代码。
HiDeskrust 是一个运行在 HarmonyOS 上的远程桌面原型项目,前端界面使用 ArkTS/ArkUI 编写,远程桌面连接、图像接收、输入转发等核心能力由 Rust 实现。
它的目标不是在 HarmonyOS 上“直接用 Rust 写应用界面”,而是:
– 用 ArkTS 负责页面、交互、状态展示和系统窗口适配
– 用 C++/N-API 负责 ArkTS 与原生代码之间的桥接
– 用 Rust 负责真正的 RDP 会话、图像帧缓存、键鼠输入和会话状态维护
换句话说,这个项目是一个“鸿蒙 UI 外壳 + 原生桥接层 + Rust 远程桌面核心”的组合架构
HarmonyOS 目前不把 Rust 当成一等应用开发语言来支持,不能像 ArkTS 一样直接把 Rust 页面或 Rust Ability 编译成应用入口。
但是 HarmonyOS 支持原生库接入,而 Rust 可以编译成标准原生静态库。因此这个项目并不是“让鸿蒙直接运行 Rust UI”,而是“把 Rust 当成原生核心库接入鸿蒙应用”。
这个项目的实现链路是:
1. Rust 代码先用 Cargo 编译为静态库 `libdemo_core.a`
2. CMake 在构建 `entry` 原生模块时,把这个静态库链接进来
3. C++ 通过头文件声明 Rust 导出的 C ABI 接口
4. `napi_init.cpp` 再把这些原生接口导出给 ArkTS
5. ArkTS 通过 `libentry.so` 调用这些接口
也就是说,Rust 在这里的身份不是“鸿蒙应用语言”,而是“被鸿蒙原生模块链接进去的核心库”。
项目根目录的主要结构如下:
HiDeskrus/
├─ AppScope/ 应用级配置
├─ entry/ HarmonyOS 主模块
│ └─ src/main/
│ ├─ ets/ ArkTS 页面与能力入口
│ │ ├─ entryability/
│ │ ├─ entrybackupability/
│ │ └─ pages/
│ │ ├─ RemoteDeskIndex.ets 当前主页面
│ │ ├─ RemoteDeskFullscreen.ets
│ │ └─ Index.ets
│ ├─ cpp/ C++ 原生桥接层
│ │ ├─ CMakeLists.txt
│ │ ├─ napi_init.cpp
│ │ ├─ rust_bridge.h
│ │ └─ types/libentry/index.d.ts
│ └─ resources/ 资源与页面入口配置
├─ rust/ Rust 核心代码
│ └─ demo-core/
│ ├─ Cargo.toml
│ └─ src/
│ ├─ lib.rs
│ ├─ real_impl.rs
│ ├─ keymap.rs
│ └─ lib_demo_legacy.rs
├─ hvigor/ 构建相关文件
├─ oh_modules/ 前端依赖
├─ build-profile.json5 构建配置
├─ hvigorfile.ts Hvigor 入口
└─ PROJECT_ARCHITECTURE.md 本文档
Rust 是怎么被接入构建流程的?
我做了几件关键事情:
- 自动定位 DevEco Studio 的 OHOS Native SDK
- 根据 ABI 选择 Rust 目标三元组
- 查找本机 `cargo`
- 设置 Rust 交叉编译所需的 linker、ar、clang、sysroot
- 通过 `add_custom_command(...)` 在 CMake 构建过程中执行 `cargo build`
- 生成 Rust 静态库后,再把它链接进 `entry` 共享库
ABI 到 Rust target 的映射
当前配置里有这样的映射关系:
- `arm64-v8a` -> `aarch64-unknown-linux-ohos`
- `x86_64` -> `x86_64-unknown-linux-ohos`
- `armeabi-v7a` -> `armv7-unknown-linux-ohos`
Rust 产物类型
在 [Cargo.toml](D:/HiDeskrus/rust/demo-core/Cargo.toml) 中:
```toml
[lib]
crate-type = ["staticlib"]
```
这表示 Rust 会被编译成一个静态库,而不是可执行文件,也不是动态库。
这样生成出来的 `libdemo_core.a` 就可以像普通 C/C++ 静态库一样被链接进 `libentry.so`。
最终链接关系
最终得到的原生层关系可以理解为:
```text
ArkTS 页面
↓
libentry.so
├─ napi_init.cpp
├─ rust_bridge.h
└─ 静态链接 libdemo_core.a
↓
Rust RDP Core
```
因此,应用真正加载的是 `libentry.so`,而 Rust 核心是作为它的一部分被带进去的。
运行时调用链
1. 建立连接
用户在 ArkTS 页面输入主机、端口、用户名、密码后:
1. `RemoteDeskIndex.ets` 组装连接配置 JSON
2. 调用 `nativeBridge.connectRdpSession(configJson)`
3. `napi_init.cpp` 把 JSON 字符串传给 Rust 的 `demo_connect_rdp_session`
4. Rust 在 `real_impl.rs` 中解析配置并启动 RDP 会话
5. Rust 将连接状态、日志、分辨率等信息写入共享状态
2. 刷新状态
前端会定期调用:
- `getSessionSnapshotJson()`
- `getEventLogJson(limit)`
- `getDisplaySettingsJson()`
Rust 把当前会话状态序列化为 JSON 返回给前端,用于更新界面。
3. 刷新画面
画面刷新链路是:
1. Rust 持有当前远端桌面的 RGBA 帧缓冲
2. ArkTS 调用 `captureSessionFrame(width, height)`
3. `napi_init.cpp` 分配 `ArrayBuffer`
4. Rust 的 `demo_fill_session_frame_rgba(...)` 把当前帧复制或缩放进这个缓冲区
5. ArkTS 把 `ArrayBuffer` 转为 `PixelMap`
6. `Image` 组件显示这张 `PixelMap`
所以前端拿到的不是“视频控件”,而是一帧一帧拉取出来的 RGBA 位图。
4. 输入转发
输入链路是:
1. ArkTS 捕获点击、拖拽、缩放和键盘事件
2. 前端把坐标归一化后调用 `sendPointerInput(x, y, actionCode)`
3. 或调用 `sendKeyInput(keyCode, isDown)`
4. Rust 将这些输入转换成 RDP 鼠标/键盘事件
5. 再通过 `ironrdp` 发给远端 Windows
[keymap.rs](D:/HiDeskrus/rust/demo-core/src/keymap.rs) 的作用就是把 HarmonyOS/ArkTS 侧的键值映射成 RDP 可识别的扫描码。
当前主页面与关键模块
页面入口
[main_pages.json](D:/HiDeskrus/entry/src/main/resources/base/profile/main_pages.json) 当前只配置了一个主页面:
- `pages/RemoteDeskIndex`
说明当前应用主体已经收敛到单页主架构,核心逻辑基本集中在 [RemoteDeskIndex.ets](D:/HiDeskrus/entry/src/main/ets/pages/RemoteDeskIndex.ets) 中。
原生导出接口定义
[index.d.ts](D:/HiDeskrus/entry/src/main/cpp/types/libentry/index.d.ts) 描述了 ArkTS 侧可直接调用的原生 API,这一层相当于 ArkTS 对原生模块的类型契约。
Rust 导出接口定义
[rust_bridge.h](D:/HiDeskrus/entry/src/main/cpp/rust_bridge.h) 声明了 C++ 要调用的 Rust 符号,例如:
- `demo_connect_rdp_session`
- `demo_get_session_json`
- `demo_get_event_log_json`
- `demo_set_display_fps`
- `demo_send_pointer_input`
- `demo_send_key_input`
- `demo_fill_session_frame_rgba`
这些都是标准 C ABI 风格接口,目的是让 Rust 和 C++ 能稳定互通。
为什么这种方案可行
从工程角度看,这种方案可行的原因有三个:
- HarmonyOS 支持 C/C++ 原生模块接入
- Rust 可以稳定导出 C ABI,并编译为静态库
- CMake 可以把 Cargo 构建过程纳入原生编译链
所以虽然 HarmonyOS 还没有“原生 Rust 应用开发栈”,但只要把 Rust 放在原生库层,就可以在鸿蒙项目里承担真正的业务核心。
这种架构的优点
- UI 与协议核心解耦,前端和核心可以分别迭代
- Rust 适合承载连接状态机、协议处理和内存安全要求高的部分
- ArkTS 继续负责鸿蒙页面、窗口、手势和系统能力对接
- 原生桥接层很薄,职责清晰,便于定位问题
目前这套架构的代价
- 构建链更复杂,需要同时维护 Hvigor、CMake 和 Cargo
- 交叉编译依赖 `cargo`、OHOS target、DevEco Native SDK 环境
- ArkTS 与 Rust 之间的数据交换要经过 JSON / ArrayBuffer / FFI,调试成本更高
- 任何一层出现状态不同步,都会影响触控、刷新或画面表现
这也是为什么这个项目的很多问题常常不是单点 bug,而是“前端事件、桥接调用、Rust 会话状态、图像刷新”四层联动问题。
所以这个项目还有很多问题,只能说作为个人学习Rust和鸿蒙开发的实验性项目,暂时不打算开源,等后期优化后打算上级华为应用市场,同时开源,敬请期待!





评论