- UID
- 5148
- 精华
- 积分
- 866
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
来源
从不知道多老开始,VB6那时候就有一个浏览器控件,WebBrower,反正用的IE内核贼垃圾。
Win10推出之后,微软的edge浏览器是用的edgeHTML这个内核,当时推出了一个浏览器控件叫 WebView 。
这个控件体验也很差,早期还只支持 UWP 不支持 WIN32 。
自从微软把edge浏览器变成了谷歌浏览器内核(Chromium),一切都开始明朗起来了。
推出了新的浏览器控件 WebView2 ,接下来我们就讲一讲怎么玩耍这个东西。
官方文档
如果你不想看我BB,直接去下面看官方文档。
https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/
安装
首先,你必须在你的电脑上安装 WebView2 Runtime。可以说你不安装新版edge只要安装这个runtime就行了,这是为了防止做出的操作对系统环境使用的 edge 造成破坏或干扰。
在软件的用户的电脑上也必须安装这个runtime才能正常工作。
https://developer.microsoft.com/en-us/microsoft-edge/webview2/
微软特地给你提供了离线安装版,在线安装版和固定不更新版本。
在线安装版,就是 Evergreen Bootstrapper。
离线安装版,就是 Evergreen Standalone Installer。
Evergreen 指的是常青的,比如常青藤(意义不明)。
这两个都只能安装到 C:\Program Files (x86)\Microsoft\EdgeWebView\Application 里面,而且好像会自动更新(具体不清楚,官方文档里写的很含糊)。
还有一个解压即用版,就是 Fixed Version ,其实指的是固定版本,这个是不会自动更新的。
如果你要使用这个 Fixed Version ,最好好好阅读一下这个 https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/distribution
安装好runtime之后,到你的 .NET 项目里面安装这个 NUGET 包。
注意只能在以下平台运行:
入门,链接跳转
下面我全部的内容使用的都是 .NET Framework 4.8 , Windows Forms, VB .NET 。
不同的版本会有小的差异。
你应该可以在这个控件工具箱列表里找到这个控件,放置出来就可以了。
尽量不要操作右边的属性栏,把要初始化的代码都写在窗体的Load里面就好。
下面我把这个控件实例命名为 edge 。
在窗体的 Load 事件里面写上:
- edge.Source = New Uri("https://www.baidu.com")
复制代码
Source 属性可以让控件跳到指定的链接。可以是 http://localhost,也可以是 file:///C:/xxx.html 格式的本地文件链接,还可以是 edge://version ,不过好像没有那个小恐龙游戏了。
运行程序,看见窗口内的浏览器控件自动跳到了百度,说明咱们成功了。
还有,别让用户手贱把这些进程给关了。
设置运行环境,保存用户数据
在不设置运行环境的情况下,默认的用户数据是保存在webview2 runtime里面的,和用户平时的edge是隔离的,但是会在所有webview2程序里共享。
如果你登陆了B站,并且选择了记住信息,那么下次打开程序还是会自动登陆B站。
要避免共享,可以设置用户数据保存的文件夹,和其他人的独立开来。
首先需要引用(如果是wpf的自己改):
- Imports Microsoft.Web.WebView2.Core
- Imports Microsoft.Web.WebView2.WinForms
复制代码
在窗体的 Load 事件里面写上:
- Dim ev = CoreWebView2Environment.CreateAsync(, AppContext.BaseDirectory)
- edge.EnsureCoreWebView2Async(ev.Result)
- edge.Source = New Uri("https://baidu.com")
复制代码
尽管这上面两个函数都是异步的,后面我会讲异步的关系。
CoreWebView2Environment.CreateAsync这个函数有三个可选参数,留空都是默认,第一个是webview2 runtime的路径,就是有msedgewebview2.exe的那个文件夹。第二个是用户数据文件夹。第三个是一些可选设置,可以添加自定义进程启动设置。
用户数据文件夹的那个路径下,webview2会创建一个文件夹叫做EBWebView,然后一切用户数据都是在里面的。
正确设置 Core
CoreWebView2 是核心,用控件的只读属性 CoreWebView2 来获得,上面说到的 EnsureCoreWebView2Async 函数就是修改这个核心的设置。
但是问题来了,这个异常奇葩,属性 CoreWebView2 获得的核心默认是 nothing (null) 的,你必须先使用 EnsureCoreWebView2Async 函数。
但是这个函数居然是个异步函数,就很刺激了。
经过我的测试,如果你直接 Task.Wait() 这个玩意会永远卡死下去。
正确的办法是这样:
- Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
- Dim ev = CoreWebView2Environment.CreateAsync(, AppContext.BaseDirectory)
- Await ev
- Dim t As Task = edge.EnsureCoreWebView2Async(ev.Result)
- Await t
- Debug.WriteLine(edge.CoreWebView2.BrowserProcessId)
- edge.Source = New Uri("https://baidu.com")
- End Sub
复制代码
能不能不设置核心就用这个控件呢?
可以是可以,很多功能就少了,垃圾微软什么奇葩设计啊,core有的功能不继承到具体实现里面。
阻止新窗口弹出
在实际使用中,这玩意会动不动打开新窗口,然后新窗口就完全不受程序控制了。所以我们可以给 core 新增一个事件,让新窗口的链接转移到本窗口里来。
把下面的代码放在上面的 `Await t` 之后,就是要保证已经 `EnsureCoreWebView2Async` 完成了。
- Dim core = edge.CoreWebView2
- AddHandler core.NewWindowRequested, Sub(ss As Object, ee As CoreWebView2NewWindowRequestedEventArgs)
- ee.Handled = True
- edge.Source = New Uri(ee.Uri)
- End Sub
复制代码
这样就可以了。
阻止用户使用浏览器自带功能
默认情况下,在网页右键是可以和普通浏览器一样打开菜单的,还居然可以打开一个F12窗口,真心NB。
如果你不想让用户这么做的话,可以在 `core.Settings` 里面修改:
- core.Settings.AreDefaultContextMenusEnabled = False
- core.Settings.AreDevToolsEnabled = False
- core.Settings.IsZoomControlEnabled = False
复制代码
第三个就是不允许用户通过 ctrl 加滚轮修改网页大小,还有一些设置自己探索一下,我就懒得说了。
在网页上运行 javascript
在窗口上新增一个按钮,然后添加下列代码:
必须使用 Async 和 Await 异步操作,Task.Wait() 或 Task.Result 都会一直卡死,无法继续!
- Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
- Dim t = edge.ExecuteScriptAsync("confirm('你是帅哥嘛?')")
- Await t
- Debug.WriteLine(t.Result)
- End Sub
复制代码
效果就是这样,然后debug那边应该会显示一个 true 或者 false ,返回的一定是字符串,如果啥都没有就是"null"了。
网页传递信息到程序
这里说的是信息指的是 WebMessage ,使用方法如下:
准备一个本地网页,随便写点什么,然后一定要在 <script> 里面写上下面这段javascript并引发与运行:
- var m = {}
- m.Age = 15
- m.Name = 'John'
- window.chrome.webview.postMessage(m)
复制代码
然后在程序代码里准备好 core,按下面这么操作,最好写在窗体Load里面。那个链接就写自己的本地html的文件链接就好。
- Dim core = edge.CoreWebView2
- core.Settings.IsWebMessageEnabled = True
- edge.Source = New Uri("file:///D:/test.html")
复制代码
接下来给 webview2 控件新建一个事件:
- Private Sub edge_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs) Handles edge.WebMessageReceived
- Debug.WriteLine(e.WebMessageAsJson)
- End Sub
复制代码
这样,在加载这个html,运行到那段js的时候,就会引发这个WebMessageReceived事件,传过来的是对象的json字符串。
抓包
这个功能很有意思啊,可以拿来获取 httponly 的 cookie 和一些奇怪的 CSRF 之类的。
首先要给core添加一条过滤规则,指定哪些链接和内容是我们要抓包的。
如果想抓全部,就写这个:
- core.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All)
复制代码
接下来需要添加一个捕获事件,就像这样:
- AddHandler core.WebResourceRequested, Sub(ss As Object, ee As CoreWebView2WebResourceRequestedEventArgs)
- If ee.Request.Headers.Contains("Cookie") Then
- Debug.WriteLine(ee.Request.Headers.GetHeader("Cookie"))
- End If
- '最好先检测一下是不是Headers.Contains
- '否则 GetHeader 遇到不存在的头会扔出一个错误。
- End Sub
复制代码
在API里,CoreWebView2WebResourceRequestedEventArgs是有一个属性叫Response,不过没有合适的办法来获取它的值,访问就是nothing(null),如果在task里或者thread里去访问这个值,直接就throw了一个COM不支持的错误出来。
github有神仙通过修改官方dll实现了获取这个`Response`,想看可以自己看看。
|
|