Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gview

一个轻量级、跨平台的 Go 语言 WebView 库(无 CGO),基于 purego 驱动。

Go Version License

gview 是 webview/webview 的 Go 语言绑定,使用 purego 实现,完全无需 CGO。它内置了 Windows、macOS 和 Linux 的原生库,开箱即用。


目录


✨ 特性

特性 描述
无 CGO 纯 Go 实现,无需安装 GCC/MinGW 等编译环境
跨平台 支持 Windows (WebView2), macOS (WebKit), Linux (WebKitGTK)
线程安全 UI 操作全链路线程安全,内置高频 Dispatch 批处理优化
现代通信 内置双向 RPC、事件总线 (EventBus) 及 SSE/WebSocket 高速数据通道
内置运行库 各平台原生库已内嵌,支持自动提取与零依赖分发
灵活配置 支持自定义提取目录、RPC 超时、日志接口及深度的性能调优
多窗口管理 内置 WindowManager 助手,轻松管理多窗口应用

🚀 核心优势

零依赖部署

得益于 purego 和内嵌资源技术,gview 实现了真正的 单文件分发。开发者只需编译一个可执行文件,即可在目标机器上自动提取并运行原生 WebView 环境。

高性能数据链路

针对不同场景设计的三层通信方案:

通道 适用场景 特点
RPC 强逻辑交互 支持返回值和错误处理,适合 API 调用
EventBus 事件广播 多窗口高效事件分发,避免冗余序列化
SSE/WebSocket 实时数据流 非阻塞推送,支持 100Hz+ 高频更新

健壮的生命周期管理

  • 内置 UI 线程调度批处理优化
  • 自动处理资源回收
  • 针对 Windows 平台处理复杂的库加载与线程锁定问题
  • 有效防止窗口"未响应"或进程残留

安全加固

  • 严格过滤 JS 注入风险
  • 本地 SSE 数据服务引入 32 字节随机 Token 验证
  • 仅允许 localhost 访问数据服务

🏗 项目架构

目录结构

gview/
├── assets/                    # 嵌入资源
│   ├── gview_core.js         # 核心 JS 库
│   ├── webview_helpers.js    # 辅助函数库
│   ├── htmx.min.js           # HTMX 库
│   ├── early_error_suppress.js
│   ├── VERSION.txt
│   ├── windows_amd64/        # Windows 原生库
│   ├── darwin_amd64/         # macOS Intel 原生库
│   ├── darwin_arm64/         # macOS ARM 原生库
│   ├── linux_amd64/          # Linux AMD64 原生库
│   └── linux_arm64/          # Linux ARM64 原生库
├── cmd/                       # 示例应用
│   ├── demo/                 # 统一演示应用
│   └── echarts/         # ECharts 集成示例
├── docs/                      # 文档
├── webview.go                 # 核心 WebView 实现
├── interfaces.go              # 接口定义
├── rpc.go                     # RPC 双向通信
├── eventbus.go                # 事件总线
├── sse.go                     # SSE/WebSocket 数据流
├── native.go                  # 原生库加载
├── native_lib.go              # 原生库符号定义
├── config.go                  # 配置
├── manager.go                 # 窗口管理器
├── embedded.go                # 资源嵌入
├── embedded_config.go         # 嵌入资源配置
├── errors.go                  # 错误定义
├── stats.go                   # 统计功能
├── dispatch.go                # 调度器
├── schema.go                  # Schema 验证
├── load_windows.go            # Windows 库加载
├── load_unix.go               # Unix 库加载
└── webview_test.go            # 测试文件

核心接口设计

type WebView interface {
    Lifecycle    // 生命周期管理 (Run, Terminate, Destroy, Done, State)
    Window       // 窗口操作 (SetTitle, SetSize, Navigate, SetHtml, Window)
    Binder       // 函数绑定 (Bind, Unbind)
    Caller       // 函数调用 (Call, Eval, EvalRaw, Dispatch)
    Emitter      // 事件发射 (Emit, EmitRaw, On, Off)
    Streamer     // 数据流 (StartDataServer, StopDataServer, SendData, StreamJSON)
    Init(js string, pattern ...string)
    RegisterSchema(event string, schema SimpleSchema)
    Context() context.Context
    GetRuntimeStats() RuntimeStats
    GetSSEStats() SSEStats
}

通信架构图

┌─────────────────────────────────────────────────────────────────┐
│                         Go Backend                               │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────┐  ┌──────────┐  ┌─────────────────────────────────┐ │
│  │   RPC   │  │ EventBus │  │      SSE / WebSocket           │ │
│  │ 双向调用 │  │  事件广播 │  │        高速数据流               │ │
│  └────┬────┘  └────┬─────┘  └───────────────┬─────────────────┘ │
│       │            │                        │                    │
│       │  Bind()    │  Subscribe()           │  SendData()        │
│       │  Call()    │  Publish()             │  StreamJSON()      │
│       ▼            ▼                        ▼                    │
├─────────────────────────────────────────────────────────────────┤
│                    purego / Native Library                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│                    WebView (Native)                              │
│                                                                  │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                    JavaScript Runtime                        ││
│  │  ┌─────────────────────────────────────────────────────────┐││
│  │  │  window.gview API                                       │││
│  │  │  • gview.call(name, ...args) → Promise                  │││
│  │  │  • gview.on(event, callback)                            │││
│  │  │  • gview.emit(event, data)                              │││
│  │  │  • gview.connectSSEAuto(options)                        │││
│  │  │  • gview.stream.start(options)                          │││
│  │  └─────────────────────────────────────────────────────────┘││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

📖 快速开始

安装

go get gview

基础示例

package main

import (
    "log"
    "gview"
)

func main() {
    w, err := gview.New(gview.DefaultConfig(), gview.WithDebug(true))
    if err != nil {
        log.Fatal(err)
    }

    w.SetTitle("GView 示例")
    w.SetSize(800, 600, gview.HintNone)
    w.SetHtml("<h1>你好,GView</h1>")

    w.Run()
}

运行示例应用

go run ./cmd/demo        # 统一演示应用
go run ./cmd/echarts  # ECharts 图表演示

📚 API 参考

窗口创建

w, err := gview.New(cfg gview.Config, opts ...gview.Option) (gview.WebView, error)

可用选项:

选项 说明
WithDebug(bool) 启用调试模式
WithWindow(unsafe.Pointer) 使用自定义原生窗口句柄
WithTitle(string) 设置窗口标题
WithSize(width, height int, hint Hint) 设置窗口大小
WithHTML(string) 设置初始 HTML
WithURL(string) 设置初始 URL
WithJSHelpers(bool) 注入 JS 辅助函数
WithAutoStream(bool) 自动启动数据流服务
WithStatusHelpers(bool) 注入状态辅助函数
WithHotkeysHelpers(bool) 注入热键辅助函数
WithLayoutHelpers(bool) 注入布局辅助函数

窗口操作

w.SetTitle(title string)
w.SetSize(width, height int, hint Hint)
w.Navigate(url string)
w.SetHtml(html string)
w.Window() unsafe.Pointer

Hint 常量:

  • HintNone - 默认
  • HintMin - 最小尺寸
  • HintMax - 最大尺寸
  • HintFixed - 固定尺寸

生命周期

w.Run()                  // 启动主循环(阻塞)
w.Terminate()            // 终止运行
w.Destroy()              // 销毁窗口
w.Done() <-chan struct{} // 获取完成通道
w.State() State          // 获取当前状态
w.Context() context.Context

State 常量:

  • StateNone - 未创建
  • StateCreated - 已创建
  • StateRunning - 运行中
  • StateTerminated - 已终止
  • StateDestroyed - 已销毁

RPC 双向通信

Go 绑定函数:

err := w.Bind("myFunc", func(a, b int) (int, error) {
    return a + b, nil
})
err := w.Unbind("myFunc")

Go 调用 JS:

result, err := w.Call("jsFunc", arg1, arg2)

JS 调用 Go:

const result = await gview.call("myFunc", 1, 2);
const detailed = await gview.callDetailed("myFunc", 1, 2);

gview.callDetailed() 返回结构化结果:成功时是 { ok: true, result, meta },失败时是 { ok: false, error, meta },其中 error.code、error.method、error.transport 可直接用于分支处理。

事件总线

Go 端:

gview.Subscribe(w, "event-name")
gview.Publish("event-name", data)
gview.Unsubscribe(w, "event-name")

w.Emit("event-name", data)
w.On("event-name", func(data any) {})
w.Off("event-name")

JS 端:

gview.on("event-name", (data) => console.log(data));
gview.emit("event-name", { key: "value" });
gview.off("event-name", callback);

数据流 (SSE/WebSocket)

port, err := w.StartDataServer(port int, handler ...func([]byte))
err := w.StopDataServer()
port := w.DataServerPort()

w.SendData([]byte(`{"value": 42}`))
w.SendDataUnsafe([]byte(data))
w.SendDataBatch([][]byte{data1, data2})
w.StreamJSON("event-name", data)

w.RegisterSchema("event-name", gview.SimpleSchema{
    Required: []string{"field1"},
    Types:    map[string]string{"field1": "string"},
})

JS 端:

window.gview.connectSSEAuto({
    transport: 'auto',
    onopen: () => console.log('Connected'),
    onmessage: (data) => console.log(data),
    onclose: () => console.log('Disconnected')
});

JavaScript 执行

w.Init(js string, pattern ...string)  // 注入初始化脚本
w.Eval(js string)                      // 执行 JS 代码
w.EvalRaw(js []byte)                   // 执行原始 JS 字节
w.Dispatch(f func())                   // 在 UI 线程执行

统计与诊断

runtimeStats := w.GetRuntimeStats()
sseStats := w.GetSSEStats()

type RuntimeStats struct {
    NumGoroutine  int
    MemAlloc      uint64
    MemTotalAlloc uint64
    MemSys        uint64
    NumGC         uint32
    LastPauseNs   uint64
}

type SSEStats struct {
    Sent       uint64
    Dropped    uint64
    Clients    int
    ClientsSSE int
    ClientsWS  int
    Published  uint64
}

⚙️ 配置详解

cfg := gview.DefaultConfig()

cfg.RPCTimeout = 30 * time.Second
cfg.RPCWorkerPoolSize = runtime.NumCPU() * 2
cfg.MaxDispatchQueueLen = 10000
cfg.MaxGoStringLen = 10 * 1024 * 1024

cfg.SSEAddr = "127.0.0.1"
cfg.SSEKeepAliveInterval = 15 * time.Second
cfg.MaxSSEClients = 32
cfg.SSEClientBuffer = 64
cfg.SSEKeepAliveAsEvent = true

cfg.StatsEnabled = true
cfg.StatsInterval = 1 * time.Second
cfg.StatsEventName = "stats"
cfg.StatsIncludeRuntime = true
cfg.StatsSampleN = 1
cfg.StatsFields = []string{}

cfg.CustomExtractDir = ""
cfg.ForceExtract = false
cfg.Debug = false
cfg.Logger = nil

🛠 进阶功能

多窗口管理

wm := gview.NewWindowManager()

wm.Add(w)
wm.Remove(w)
wm.Has(w)
wm.Count()
wm.All()

wm.Broadcast("event", data)
wm.CloseAll()
wm.TerminateAll()

内置 JS 库

htmxJS := gview.HTMXJS()
helpersJS := gview.HelpersJS()
coreJS := gview.CoreJS()
version := gview.Version()

运行时资源配置

cfg := gview.GetEmbeddedConfig()
cfg.HTMX.UseExternal = true
cfg.HTMX.ExternalPath = "custom/htmx.min.js"
cfg.NativeLib.UseExternal = true
cfg.NativeLib.ExternalPath = "custom/webview.dll"
cfg.CustomExtractDir = "./libs"
cfg.ForceExtract = true

📦 编译与部署

标准编译

go build -o myapp .

Windows 隐藏控制台

go build -ldflags="-H windowsgui" -o myapp.exe .

禁用内嵌库(减小体积)

go build -tags no_embedded -o myapp .

使用此标签时,需确保原生库文件存在于可执行文件目录或系统路径。

交叉编译

GOOS=windows GOARCH=amd64 go build -o myapp.exe .
GOOS=darwin GOARCH=arm64 go build -o myapp .
GOOS=linux GOARCH=amd64 go build -o myapp .

⚡ 性能优化

自适应背压控制

系统自动检测客户端处理能力:

  • 丢包率过高时自动启用数据合并模式
  • 稳定后自动恢复正常传输
  • 无需手动实现节流

高频数据优化

w.SendDataBatch([][]byte{data1, data2, data3})

ECharts 集成优化

参考 docs/ECHARTS_INTEGRATION.md:

  • 使用增量更新 API
  • 限制数据点数量
  • 开启 large 模式
  • 利用 GView 自适应背压控制

🖥 平台支持

平台 渲染引擎 依赖
Windows 10/11 WebView2 (Edge Chromium) WebView2 Runtime(通常已内置)
macOS 10.15+ WebKit (Cocoa) 系统内置
Linux WebKitGTK 需安装 libwebkit2gtk-4.0

Linux 依赖安装

sudo apt install libwebkit2gtk-4.0-dev

❓ 常见问题

Q: 窗口显示黑屏?

确保已安装平台依赖:

  • Windows: WebView2 Runtime
  • Linux: WebKitGTK

Q: RPC 调用超时?

检查 RPCTimeout 配置,确保 JS 函数存在且可调用。

Q: 数据流连接失败?

检查 Token 是否正确,确保使用 window.__GO_DATA_TOKEN__。

Q: Windows 编译后体积过大?

使用 -tags no_embedded 并手动分发原生库。

Q: 如何调试?

设置环境变量 GVIEW_DEBUG=1 或使用 WithDebug(true)。


📄 许可证

MIT License


🔄 更新日志

v0.1.0 (当前版本)

核心功能:

  • 无 CGO 的 WebView 绑定
  • 双向 RPC 通信
  • EventBus 事件总线
  • SSE/WebSocket 双协议数据流
  • 多窗口管理
  • 内置 HTMX 支持
  • 自适应背压控制
  • Schema 验证
  • 运行时统计

示例应用:

  • 统一演示应用 (cmd/demo)
  • ECharts 集成示例 (cmd/echarts)

About

极简webview界面,适用简洁桌面应用

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages