当前位置: 首页 > news >正文

用 Go + HTML 实现 OpenHarmony 投屏(hdckit-go + WebSocket + Canvas 实战)

本文带你用 Go + HTML/WebSocket 从零实现一个 OpenHarmony 设备投屏 Demo:Go 侧用 hdckit-go 连接设备并抓取屏幕帧(UiDriver),通过 WebSocket 二进制实时推送到浏览器,前端用 Canvas 渲染,并根据设备分辨率自适应显示。

  • 源码:GitHub - airhandsome/hdckit-go-demo
  • hdckit-go 项目地址:GitHub - airhandsome/hdckit-go

一、功能概览

  • 设备发现:通过 hdckit-go 列出 HDC 可连接设备
  • 屏幕捕获:UiDriver 启动后回调获取 JPEG 帧
  • 实时传输:WebSocket 二进制帧推送
  • 前端渲染:Canvas 使用 createImageBitmap + requestAnimationFrame 平滑绘制
  • 自适应缩放:根据设备原始分辨率动态调整 Canvas 样式尺寸
  • 可扩展:可继续加按键/触控映射、录屏、帧率调节等

二、整体架构

  • Go 后端
  • hdc.NewClient → Target → CreateUiDriver → Start → StartCaptureScreen
  • WebSocket 端点 /ws 推送二进制 JPEG 帧;REST 接口 /api/devices 获取设备列表,/api/devices/{key}/start|stop 控制投屏
  • 前端
  • WebSocket 连接服务器(binaryType = 'arraybuffer')
  • 收到 ArrayBuffer(二进制帧)→ createImageBitmap → requestAnimationFrame → Canvas 绘制
  • 按容器大小与原始分辨率等比缩放显示

三、后端实现要点(Go)

依赖:

  • github.com/airhandsome/hdckit-go/hdc
  • github.com/gorilla/websocket

核心流程:

1) 初始化 HDC Client

cli := hdc.NewClient(hdc.Options{}) // 可配置 Bin/Host/Port
hdcClient = cli

2) 列出设备

targets, _ := hdcClient.ListTargets(ctx)
// 组装为 Device 列表返回给前端

3) UiDriver 投屏

drv := hdcClient.Target(deviceKey).CreateUiDriver()
_ = drv.Start(ctx)
_, _ = drv.StartCaptureScreen(ctx, func(frame []byte) {// 直接推送二进制帧(JPEG)broadcastBinaryFrame(frame)
}, 1)

4) WebSocket 广播二进制帧

func broadcastBinaryFrame(frame []byte) {for c := range clients {_ = c.WriteMessage(websocket.BinaryMessage, frame)}
}

5) 停止投屏

_ = drv.StopCaptureScreen(ctx)
drv.Stop() // 无参

常见坑:

  • drv.Stop() 不接受 context.Context,注意函数签名
  • 初次使用 UiDriver 需确保 uitest agent 可推送到设备(uitestkit_sdk/uitest_agent_v1.1.0.so)

四、前端实现要点(HTML/JS)

1) WebSocket 设置为二进制

ws = new WebSocket(`ws://${location.host}/ws`);
ws.binaryType = 'arraybuffer';

2) 消息处理:区分 JSON(设备列表)与二进制帧

ws.onmessage = (event) => {const data = event.data;if (typeof data === 'string') {// 设备列表等 JSON 文本const msg = JSON.parse(data);handleMessage(msg);} else if (data instanceof ArrayBuffer) {renderFrame(data);}
};

3) Canvas 渲染(平滑且防闪)

async function renderFrame(buffer) {if (!isCapturing) return;const blob = new Blob([buffer], { type: 'image/jpeg' });const bitmap = await createImageBitmap(blob);// 源尺寸imgNaturalWidth = bitmap.width;imgNaturalHeight = bitmap.height;// 仅在尺寸变化时调整样式尺寸ensureCanvasDisplaySize();// rAF 合批绘制,避免频繁同步 drawscheduleDraw(bitmap); // 内部 drawImage(bitmap, 0, 0)
}

4) 自适应缩放

  • Canvas 内部像素尺寸使用原始分辨率(canvas.width/height = naturalWidth/Height)
  • Canvas 样式使用缩放后的宽高(canvas.style.width/height),只在容器或源尺寸变化时更新

五、如何运行

1) 准备环境

  • 安装 Go 1.21+
  • 安装 HDC 并配置环境变量(可用 hdc version 验证)
  • 连接 OpenHarmony 设备(USB 或 Wi-Fi)
  • 确保 uitestkit_sdk/uitest_agent_v1.1.0.so 可用(hdckit-go 会自动推送)

2) 启动 Demo

go mod tidy
go run demo.go

3) 打开浏览器访问

http://localhost:8080
  • 左侧选择设备 → 点击“开始投屏” → 右侧 Canvas 显示实时画面

六、常见问题与排查

  • 页面黑屏/无画面
  • 是否收到了二进制帧(开发者工具 Network 或在 renderFrame 里 console.log(buffer.byteLength))
  • UiDriver 是否成功 Start/StartCaptureScreen(后端日志)
  • 设备端是否推送/运行 uitest agent
  • 画面闪烁
  • 已通过 createImageBitmap + requestAnimationFrame + 尺寸惰性更新 处理,多数场景可消除抖动
  • 帧率过高 + 分辨率大 → 建议后端降低帧率或做节流(可以丢弃落后的帧)
  • 画面比例不对
  • 确保 ensureCanvasDisplaySize() 使用的是容器尺寸与原始分辨率做等比缩放
  • 触控映射要用显示尺寸反算到原始像素坐标

七、可扩展方向

  • 触控/按键映射:后端用 hdc shell input 或 UiDriver 输入能力实现
  • 录屏/录像:将帧写入视频编码器(FFmpeg / WebCodecs)
  • OSD/标记:Canvas 上叠加调试信息/热点区域
  • 帧传输压缩与安全:考虑使用 WebSocket over TLS + GOP/帧内压缩策略

八、结语

本文提供了一个“能跑、可扩展、易维护”的投屏基础方案:Go 侧 hdckit-go 负责连接与采集、WebSocket 推二进制帧;前端 Canvas 以高效方式渲染。你可以在此基础上继续拓展全链路控制能力(UI 自动化、按键/触控、录屏等),构建自己的 OpenHarmony 设备调试控制台。

参考项目:

  • hdckit-go(airhandsome)

文章转载自:

http://sGSRGtMz.cbpkr.cn
http://tHaFUtbH.cbpkr.cn
http://JkoTqg3d.cbpkr.cn
http://UQObO5m8.cbpkr.cn
http://0KcmRmTM.cbpkr.cn
http://fIFbpz5N.cbpkr.cn
http://WPBwhCKr.cbpkr.cn
http://BQbAsq5A.cbpkr.cn
http://lNdniX7c.cbpkr.cn
http://kjdffUUp.cbpkr.cn
http://k5qcTbho.cbpkr.cn
http://sdAYW5wQ.cbpkr.cn
http://nXDq6F2I.cbpkr.cn
http://n5k5hUvo.cbpkr.cn
http://4mrxNrpm.cbpkr.cn
http://TP34FJ1S.cbpkr.cn
http://AjlpRqz5.cbpkr.cn
http://coL3G3iv.cbpkr.cn
http://2VhKoSmm.cbpkr.cn
http://eoD1LG5G.cbpkr.cn
http://0GxlquOJ.cbpkr.cn
http://DwUgFPCw.cbpkr.cn
http://MiRsYtst.cbpkr.cn
http://4V0tpPBl.cbpkr.cn
http://dD5pJMLT.cbpkr.cn
http://hj3C2Xu7.cbpkr.cn
http://IfIj1Mas.cbpkr.cn
http://1gsChtbF.cbpkr.cn
http://dHD3SkwV.cbpkr.cn
http://eCfBtFcY.cbpkr.cn
http://www.dtcms.com/a/370068.html

相关文章:

  • 《sklearn机器学习——聚类性能指标》Silhouette 系数
  • 什么是CSS
  • 【FastDDS】 Entity Policy 之 标准Qos策略
  • `IntersectionObserver`延迟加载不在首屏的自动播放视频/图片/埋点/
  • 笔记:ubuntu安装matlab
  • [linux仓库]性能加速的隐形引擎:深度解析Linux文件IO中的缓冲区奥秘
  • 【Redis】--持久化机制
  • 机器人控制器开发(导航算法——导航栈关联坐标系)
  • Linux系统编程守护进程(36)
  • 基于STM32单片机的酒驾检测设计
  • CodeBuddy 辅助重构:去掉 800 行 if-else 的状态机改造
  • Paimon——官网阅读:文件系统
  • 数据仓库概要
  • 【C++上岸】C++常见面试题目--算法篇(第二十期)
  • PyTorch生成式人工智能——深度分层变分自编码器(NVAE)详解与实现
  • Whismer-你的定制化AI问答助手
  • Paimon——官网阅读:配置
  • FPGA会用到UVM吗?
  • 电脑外接显示屏字体和图标过大
  • 深入浅出 HarmonyOS ArkUI 3.0:基于声明式开发范式与高级状态管理构建高性能应用
  • 如何在路由器上配置DHCP服务器?
  • 计算机网络:网络设备在OSI七层模型中的工作层次和传输协议
  • Unity 如何使用ModbusTCP 和PLC通讯
  • Ribbon和LoadBalance-负载均衡
  • 性能监控shell脚本编写
  • 基于SpringBoot和uni-app开发的陪诊陪护软件系统源码
  • 记一次uniapp+nutui-uniapp搭建项目
  • 计算机网络:物理层---物理层的基本概念
  • 【Java】抽象类和接口对比+详解
  • 校园管理系统|基于SpringBoot和Vue的校园管理系统(源码+数据库+文档)