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

golang调用webview,webview2,go-webview2

go version go1.20 windows/amd64

先要了解一些第三方库

1、webview/webview

它是一个跨平台的轻量级的webview库,面向的是C/C++,使用它可以构建跨平台的GUI。webview就是浏览器内核,在不同操作系统上是不同的库,比如在windows上为webview2,所以webview与webview2不要搞混了。从功能上,它实现了Javascript与C/C++之间的相互调用,即bindings。具体实现原理应该与wails差不多。

在不同平台上的支持如下

PlatformTechnologies
LinuxGTK, WebKitGTK
macOSCocoa, WebKit
WindowsWindows API, WebView2

windows api 是windows系统提供的DLL(user32.dll),以此来构建windows上原生的GUI程序。

webview2是微软的Edge浏览器内核,用它来渲染前端页面,下载地址,所以这是两种不同的实现方式。而且webview2只支持windows系统。如果你的系统是Windows 10+,那么 WebView2 Runtime会默认安装了。

2、webview/webview_go

它使用Golang将webview/webview包装了一下,但是使用的是CGO,即webview/webview_go依赖于webview/webview,并使用CGO将依赖引入。

项目还不完善,我的本地系统x86_64-w64-mingw32下面找不到EventToken.h头文件,所以代码无法运行,Support for EventToken.h on mingw64 #45 依然没有解决。

3、jchv/go-webview2

它借鉴了webview/webview,使用Golang包装了webview2,不需要使用CGO,这是与webview_go的不同,当然此包只支持windows,因为它只是包装了webview2。在wails中使用的就是 jchv/go-webview2

它提供了一个示例:cmd/demo/main.go

import ("log""github.com/jchv/go-webview2"
)func main() {w := webview2.NewWithOptions(webview2.WebViewOptions{Debug:     true,AutoFocus: true,WindowOptions: webview2.WindowOptions{Title:  "Minimal webview example",Width:  800,Height: 600,IconId: 2, // icon resource idCenter: true,},})if w == nil {log.Fatalln("Failed to load webview.")}defer w.Destroy()w.SetSize(800, 600, webview2.HintFixed)w.Navigate("https://en.m.wikipedia.org/wiki/Main_Page")w.Run()
}

在这里插入图片描述

在这里插入图片描述

go-webview2简要说明

webviewloader\module.go

先使用windows.NewLazyDLL("WebView2Loader")加载WebView2Loader.dll,如果没有找到,它会使用go-winloader库来加载go-webview2自带的WebView2Loader.dll文件(webviewloader/sdk/x64下)。

webview2的参考文档:https://learn.microsoft.com/zh-cn/microsoft-edge/webview2/

go-webview2基本已经封装的很好了,下面是一个WebView对象提供的功能。

// WebView is the interface for the webview.
type WebView interface {// Run runs the main loop until it's terminated. After this function exits -// you must destroy the webview.Run()// Terminate stops the main loop. It is safe to call this function from// a background thread.Terminate()// Dispatch posts a function to be executed on the main thread. You normally// do not need to call this function, unless you want to tweak the native// window.Dispatch(f func())// Destroy destroys a webview and closes the native window.Destroy()// Window returns a native window handle pointer. When using GTK backend the// pointer is GtkWindow pointer, when using Cocoa backend the pointer is// NSWindow pointer, when using Win32 backend the pointer is HWND pointer.Window() unsafe.Pointer// SetTitle updates the title of the native window. Must be called from the UI// thread.SetTitle(title string)// SetSize updates native window size. See Hint constants.SetSize(w int, h int, hint Hint)// Navigate navigates webview to the given URL. URL may be a data URI, i.e.// "data:text/text,<html>...</html>". It is often ok not to url-encode it// properly, webview will re-encode it for you.Navigate(url string)// SetHtml sets the webview HTML directly.// The origin of the page is `about:blank`.SetHtml(html string)// Init injects JavaScript code at the initialization of the new page. Every// time the webview will open a the new page - this initialization code will// be executed. It is guaranteed that code is executed before window.onload.Init(js string)// Eval evaluates arbitrary JavaScript code. Evaluation happens asynchronously,// also the result of the expression is ignored. Use RPC bindings if you want// to receive notifications about the results of the evaluation.Eval(js string)// Bind binds a callback function so that it will appear under the given name// as a global JavaScript function. Internally it uses webview_init().// Callback receives a request string and a user-provided argument pointer.// Request string is a JSON array of all the arguments passed to the// JavaScript function.//// f must be a function// f must return either value and error or just errorBind(name string, f interface{}) error
}

Navigate方法的参数

  • 网络地址:https://en.m.wikipedia.org/wiki/Main_Page
  • 文件系统地址:file:///D:/dev/php/magook/trunk/server/go-webview/test.html,要使用绝对地址。当然,只要是浏览器能识别的文件都行,比如图片,网页,TXT文件等等。
  • 直接展示内容:就是将文件的内容复制进去,此时就需要指定内容是什么形式的,如果不指定就无法展示出来。格式为mimetype,content,其中 mimetype的常用的有data:image/gif, data:image/webp, data:image/jpeg, data:image/png, data:text/html, data:text/text,它会严格按照mimetype渲染,所以类型一定要对。
    但是不推荐这种用法,我发现它会将本行中#后面的内容当做注释舍弃掉,比如
......
let option_CrGrDQTOQuKK = {"color":["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],"legend":{},"series":[{"name":"Category A","type":"bar","data":[{"value":235},{"value":41},{"value":90},{"value":256},{"value":202},{"value":40},{"value":11}]},{"name":"Category B","type":"bar","data":[{"value":277},{"value":69},{"value":158},{"value":274},{"value":116},{"value":43},{"value":233}]}],"title":{"text":"My first bar chart generated by go-echarts","subtext":"It's extremely easy to use, right?"},"toolbox":{},"tooltip":{},"xAxis":[{"data":["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]}],"yAxis":[{}]}
......

你会发现这一行只剩下了let option_CrGrDQTOQuKK = {"color":[",肯定会影响结果的。所以,最好使用前两种方式。

Bind 方法,进行了绑定之后,js就可以调用name方法,而这个name方法在go中的实现逻辑就是 f。

func (w *webview) Bind(name string, f interface{}) error {v := reflect.ValueOf(f)if v.Kind() != reflect.Func {return errors.New("only functions can be bound")}if n := v.Type().NumOut(); n > 2 {return errors.New("function may only return a value or a value+error")}w.m.Lock()w.bindings[name] = fw.m.Unlock()w.Init("(function() { var name = " + jsString(name) + ";" + `var RPC = window._rpc = (window._rpc || {nextSeq: 1});window[name] = function() {var seq = RPC.nextSeq++;var promise = new Promise(function(resolve, reject) {RPC[seq] = {resolve: resolve,reject: reject,};});window.external.invoke(JSON.stringify({id: seq,method: name,params: Array.prototype.slice.call(arguments),}));return promise;}})()`)return nil
}

它这里使用的是window.external.invoke()方法,即调用外部方法,因为它包装的是new Promise,所以使用 Promise 的机制来处理返回值。

在RPC调用方面,其内部机制还是postMessage()消息事件,更具体的可以阅读我关于wails的文章。

如果 Debug = true,那么按F12可以打开调试。

我的代码如下:

package mainimport ("errors""log"webview2 "github.com/jchv/go-webview2"
)func main() {w := webview2.NewWithOptions(webview2.WebViewOptions{Debug:     true,AutoFocus: true,WindowOptions: webview2.WindowOptions{Title:  "Minimal webview example",Width:  800,Height: 600,IconId: 2, // icon resource idCenter: true,},})if w == nil {log.Fatalln("Failed to load webview.")}defer w.Destroy()w.Bind("test_love", Great)w.Navigate("file:///D:/dev/php/magook/trunk/server/go-webview/test.html")w.Run()
}func Great(param string) (result string, err error) {if param == "I love you" {return "I love you too", nil} else if param == "I hate you" {return "", errors.New("break up")} else {return "I don't know", nil}
}

特别注意: Bind() 一定要在 Navigate() 之前调用,否则就是无效的!!

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>爱吗?</title>
</head><body><div class="box"><input type="button" value="爱你" class="btn" onclick="love()"><input type="button" value="不爱了" class="btn" onclick="nolove()"></div>
</body></html>
<style>.box {margin-top: 100px;text-align: center;}.btn {display: inline-block;width: 100px;height: 50px;border-radius: 10px;border: 2px solid green;text-align: center;}
</style>
<script>function love() {window["test_love"]("I love you").then(result => {alert(result);}).catch(err => {alert(err);});}function nolove() {window["test_love"]("I hate you").then(result => {alert(result);}).catch(err => {alert(err);});}
</script>

打开调试,console.log(window),或者 console.log(window.test_love),就能看到你定义的方法已经被注册到了window对象上。

运行效果:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由于wails引入了go-webview2,并做了扩展,所以直接使用wails框架即可。


http://www.mrgr.cn/news/77672.html

相关文章:

  • 【分享一个vue指令】复制指令v-copy
  • 20241121 android中树结构列表(使用recyclerView实现)
  • 设计模式:4、命令模式(双重委托)
  • Altium Designer学习笔记 11-15 原理图的封装 编译 检查 _PCB封装库的创建
  • Android Studio 设置不显示 build-tool 无法下载
  • 各种语言书籍下载
  • leetcode-44-通配符匹配
  • 【web前端笔记】vue3 + vite的前端项目中,使用import.meta.glob()方法实现全局注册组件的通用代码
  • Linux从入门到精通
  • wsl使用
  • Node.js
  • Spring:IOC实例化对象bean的方式
  • 第二十二章 TCP 客户端 服务器通信 - TCP设备的OPEN和USE命令关键字
  • 【算法速刷(10/100)】LeetCode —— 23. 合并 K 个升序链表
  • Linux---shell脚本
  • Spring Batch :高效处理海量数据的利器
  • 15分钟学 Go 第 56 天:架构设计基本原则
  • 【操作系统不挂科】<Linux进程概念>选择题(带答案与解析)
  • shell数组
  • 预处理(1)(手绘)