基于Rust和RDP协议的鸿蒙远程桌面软件
本文最后更新于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和鸿蒙开发的实验性项目,暂时不打算开源,等后期优化后打算上级华为应用市场,同时开源,敬请期待!
文末附加内容

评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇