极空间桌面系统实现:Qt 壳 + Web 内容 + 原生播放器

2026/05/22

基于 xnasdesktop、pcweb、player-qt、hdmi-h5 等组件的逆向分析 分析日期:2026-05-22

说明:本篇写于 Web 桌面技术栈确认之前,文中"React + Vue.js 混合"的判断已被第 6 篇修正——pcweb 实际是纯 Vue 3 应用。本篇的价值在于 HDMI 桌面(Qt 壳)、原生播放器和 Web-Native 通信机制的分析,这些结论不受影响。


一、核心结论:Qt 壳 + Web 内容 + 原生播放器的混合架构

极空间的"桌面系统"有两套实现,但共享同一套 Web 前端代码:

┌─────────────────────────────────────────────────────┐
│                   桌面系统入口                         │
│                                                      │
│  ┌──────────────────┐    ┌──────────────────────┐   │
│  │  浏览器访问        │    │  HDMI 输出(接电视/显示器)│   │
│  │  :80 / :8080      │    │  xnasdesktop 原生应用    │   │
│  └────────┬─────────┘    └───────────┬──────────┘   │
│           │                          │               │
│           ▼                          ▼               │
│  ┌──────────────────┐    ┌──────────────────────┐   │
│  │  pcweb (SPA)     │    │  xnasdesktop (Qt5)   │   │
│  │  nginx 静态文件   │    │  + Chromium WebView   │   │
│  │                  │    │  + 原生 Qt 播放器      │   │
│  └────────┬─────────┘    └───────────┬──────────┘   │
│           │                          │               │
│           └──────────┬───────────────┘               │
│                      │                               │
│                      ▼                               │
│          ┌───────────────────────┐                   │
│          │  同一套 Web 前端代码    │                   │
│          │  Vue 3 + Vue Router + │                   │
│          │  ECharts              │                   │
│          └───────────────────────┘                   │
└─────────────────────────────────────────────────────┘

二、xnasdesktop:原生 Qt 桌面壳

是什么

xnasdesktop 是一个 Qt5 C++ 桌面应用,安装在 /zspace/applications/services/xnasdesktop/。它不是 Electron,而是直接用 Qt5 写的原生应用 + 系统 Chromium 做 WebView。

关键文件

文件大小作用
xnasdesktop3.3MB桌面壳主程序
xnasdesktop-daemon5.0MB后台守护进程
pdfview141KB原生 PDF 阅读器
libQt5*.so约 50MB自带的 Qt5 运行时库

打包方式

使用 linuxdeployqt 工具打包,所有 Qt 依赖自包含:

qt.conf:
[Paths]
Prefix = ./
Plugins = plugins
Imports = qml

不依赖系统 Qt,升级时可整体替换。

启动流程

# realstart.sh — 桌面壳启动逻辑
export DISPLAY=:0.0
export QTWEBENGINE_DISABLE_SANDBOX=1  # Qt WebEngine 以 root 运行
export GST_MPP_VIDEODEC_DEFAULT_ARM_AFBC=1  # Rockchip 硬解

killall chromium-bin  # 清理残留
./xnasdesktop-daemon &  # 启动守护进程

关键点:xnasdesktop-daemon 是实际启动的进程,它负责:

桌面配置

# conf.ini
[Player]
Path=/zspace/applications/services/xnasplayer/  # 原生播放器路径

[Xnas]
UseChrome=1                                       # 使用 Chromium 渲染 Web
Url="http://127.0.0.1:20123/home?locale=zh_cn"    # Web UI 地址
Wallpaper=/zspace/system/resource/T2_default.jpg  # 壁纸路径
ChromeStartType=0                                  # Chromium 启动模式
Locale=zh_cn                                       # 语言
LockBaseTime=60000                                 # 锁屏时间

当前设备状态

// daemon.json
{"enable_desktop": false}

被分析 T2 的 HDMI 桌面是关闭状态(T2 是便携 NAS,通常不接显示器)。

机型判断逻辑:

# T022 型号禁用桌面(某些低端型号无 HDMI 输出)
if grep -qE "T022" "$ID_FILE"; then
    echo "xnasdesktop disabled on zspace t022"
    exit 0
fi

三、pcweb:Web 桌面 SPA

是什么

pcweb 是一个单页应用(Vue 3,见第 6 篇),由 nginx 提供静态文件服务。这是用户在浏览器中看到的桌面界面。

打包产物

库文件用途
Vue 3lib-vue.dc72da37.js核心框架
Vue Routerlib-router.22ab4569.js前端路由
Axioslib-axios.b14a43f9.jsHTTP 请求
EChartsecharts.ab94bd45.js图表(系统监控等)

多入口架构

pcweb 为不同场景提供不同的入口:

/zspace/applications/services/pcweb/
├── home/
│   ├── index.html           ← PC 浏览器入口
│   ├── index-abroad.html    ← 海外版入口
│   ├── index-local.html     ← 局域网入口
│   ├── mobile/              ← 手机浏览器入口
│   └── static/js/           ← 打包后的 JS/CSS
│       ├── index.c3f6052c.js       主包
│       ├── lib-vue.dc72da37.js     Vue 运行时
│       ├── lib-router.22ab4569.js  Vue Router
│       ├── lib-axios.b14a43f9.js   HTTP 客户端
│       └── echarts.ab94bd45.js     ECharts 图表
│
└── AppH5/
    ├── index.html            ← App 内嵌 H5 入口
    └── static/               ← 独立的打包产物

应用路由:nginx Lua 动态分发

pcweb 最精巧的设计是应用路由。访问 /home/video 时,nginx 用 Lua 动态路由到对应应用的前端:

location /home/ {
    access_by_lua_block {
        local path_mapping = {
            album = "photoAlbum",     # /home/album → photoAlbum 应用
            video = "video",          # /home/video → video 应用
            music = "music",          # /home/music → music 应用
            download = "downloads",   # /home/download → downloads 应用
            ddns = "ddns",
            onlyoffice = "onlyoffice",
            camera = "camera",
            backupCenter = "backupCenter",
            deepSeek = "deepseek",
            converter = "imgProcessing",
            classroom = "zclasses",
            -- ... 等约 25 个应用映射
        }
        -- 动态构造目标路径
        -- /home/video → /var/appstore/pkg/video/ui/apphome_video/index.html
        -- 如果目标文件存在 → 302 重定向
        -- 不存在 → 回退到 pcweb 自身的 SPA 路由
    }
}

这意味着:

子应用的 Web UI 位置

/var/appstore/pkg/video/ui/apphome_video/index.html
/var/appstore/pkg/photoAlbum/ui/apphome_photoAlbum/index.html
/var/appstore/pkg/music/ui/apphome_music/index.html
/var/appstore/pkg/downloads/ui/apphome_downloads/index.html
...

每个子应用独立打包,可以单独更新。


四、HDMI 桌面:Qt 壳 + Chrome WebView 的混合

架构

xnasdesktop 启动后:

  1. 渲染壁纸(T2_default.jpg)
  2. 启动 Chromium 浏览器进程
  3. Chromium 全屏打开 http://127.0.0.1:20123/home
  4. 20123 端口是专门的 HDMI nginx 入口,代理到 hdmi-h5 前端
xnasdesktop (Qt5 壳)
    │
    ├── 壁纸层 (Qt QPainter/QML)
    ├── 系统托盘 / 状态栏 (Qt Widgets)
    │
    └── Chromium (全屏 WebView)
         │
         └── http://127.0.0.1:20123/home
              │
              └── nginx → /zspace/applications/services/hdmi-h5/home/
                   │
                   └── 同一套 Web 前端代码 (hdmi-h5 版本)

为什么不直接用 Electron?

Electron 在 ARM 上体积太大(200MB+),且自带 Chromium 无法复用系统的硬件解码。极空间的做法更轻量:

hdmi-h5:HDMI 版本的 Web 前端

/zspace/applications/services/hdmi-h5/home/
├── index.html          ← HDMI 桌面入口
├── qwebchannel.js      ← Qt WebChannel 通信桥
└── static/
    ├── css/
    ├── js/
    └── version

qwebchannel.js 是关键——这是 Qt WebChannel 的 JavaScript 库,用于 Web 页面和 Qt 原生代码之间的双向通信。这意味着 Web UI 可以调用原生 Qt 功能(比如打开原生播放器、读取系统状态)。

两个 HDMI nginx 端口

端口用途前端源
20123HDMI 桌面 WebView 访问hdmi-h5
8088外网访问 HDMI 桌面(远程控制)hdmi-h5

两个端口配置几乎相同,只是 20123 只监听 localhost(只给本地 Chromium 用),8088 可以被远程访问(通过 5056 代理)。


五、原生播放器:为什么需要 Qt 写播放器

player-qt(主播放器)

/zspace/applications/services/player-qt/
├── player-qt          ← 8.8MB Qt5 播放器
├── player-daemon      ← 7.8MB 播放守护进程
├── libQt5*.so         ← 自包含 Qt5 库
├── libavcodec.so.58   ← FFmpeg 编解码
├── libavformat.so.58
└── libavutil.so.56

配置显示使用了 Rockchip 平台的硬件能力:

[plane-id]
AFBC=1          # ARM FrameBuffer Compression(Rockchip GPU 特性)
video=71         # 视频图层 ID
info=116         # UI 图层 ID

[play-info]
hdr=1           # HDR 支持

xnasplayer(轻量播放器)

[plane]
AFBC=1
video=68         # 视频图层
ui=102           # UI 图层

[player]
hdr=1
kms=0            # 使用 DRM 还是 KMS

为什么不用 Web 播放器?

ARM 设备上用 <video> 标签播 4K HDR 视频体验很差。原生 Qt 播放器直接调用:

同样的视频,Web 播放可能 CPU 100% 还卡顿,原生 Qt 播放器 CPU 5% 流畅播放。


六、Web 前端与原生 Qt 的通信机制

qwebchannel.js 暴露了通信桥。典型交互:

Web UI (SPA)                      Qt 壳 (xnasdesktop)
     │                                  │
     ├── 用户点击播放视频                │
     │   qwebchannel.send({             │
     │     action: "play",              │
     │     file: "/data/video.mp4"      │
     │   })                             │
     │─────────────────────────────────►│
     │                                  ├── 启动 xnasplayer
     │                                  │   exec("./xnasplayer video.mp4")
     │                                  │
     │   qwebchannel.onMessage({        │
     │     event: "playback_started"    │
     │   })                             │
     │◄─────────────────────────────────│

这种模式让 Web 技术栈负责 UI 交互,原生 Qt 负责性能敏感的媒体处理。


七、桌面系统的完整布局

用户看到的桌面
    │
    ├── 浏览器访问 (任意设备)
    │     │
    │     └── nginx :80 / :8080
    │           │
    │           ├── / → pcweb/home/index.html (SPA 主框架)
    │           ├── /home/video → /var/appstore/pkg/video/ui/ (子应用 Web UI)
    │           ├── /home/album → /var/appstore/pkg/photoAlbum/ui/
    │           ├── /home/music → /var/appstore/pkg/music/ui/
    │           └── ...
    │
    └── HDMI 输出 (接电视/显示器)
          │
          └── xnasdesktop (Qt5 桌面壳)
                │
                ├── 桌面壁纸 (QPainter 渲染)
                ├── 状态栏 / 系统托盘 (Qt Widgets)
                ├── Chromium WebView (全屏)
                │     │
                │     └── http://127.0.0.1:20123/home
                │           │
                │           └── hdmi-h5 前端 (与 pcweb 共享代码)
                │
                ├── 原生视频播放器 (player-qt / xnasplayer)
                │     直接调用 GPU 硬解码 (Rockchip MPP + DRM)
                │
                └── 原生 PDF 阅读器 (pdfview)

八、技术选型分析

极空间的桌面方案有几个聪明的选择:

1. Qt5 而非 Electron

2. 不强制统一框架

3. Web 优先,原生辅助

4. hdmi-h5 和 pcweb 代码共享


九、如果要自己实现类似方案

推荐的路径:

Phase 1(Web only)

Phase 2(Hybrid — HDMI 输出)

Phase 3(性能优化)

如果必须用 Qt(比如需要深度的硬件集成),可以参考 xnasdesktop 的做法:

  1. 自包含 Qt 库(linuxdeployqt 打包)
  2. Qt WebEngine 做 WebView
  3. Qt WebChannel 做 JS-Native 桥
  4. 原生播放器单独进程,通过 IPC 与桌面壳通信