本文帶你用 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)