原想编译 chromium 定制个浏览器,结果搞半天发现真不是一般的费劲啊,算啦,额们这菜鸟,还是直接套个Microsoft 家的 Webview2 吧,又简单又快捷,加个外壳改改皮肤就行了,虽然并没什么卵用☺☺☺☺。
最终效果
具体实现步骤
1. winform 搭个外壳并添加webview2组件
打开 visual studio 2019,新建一个 c# 的 windows窗体应用
工具-NuGet包管理-搜索安装 webview2,加入项目,安装
返回窗体设计器-WebView2-拖动winforms的webview2控件到窗体中合适位置,name=webView21
设置窗体属性-Source,即打开浏览器默认的网址,比如我这里设置的是 juejin
2. 添加 后退 前进 地址栏 go 等按钮
添加3个button控件,分别是 后退按钮、前进按、go按钮和地址栏
双击 后退按钮,绑定 GoBack() 事件,实现后退功能
private void goback_Click(object sender, EventArgs e)
{
webView21.GoBack();
}
复制代码
双击 前进按钮,绑定 GoForward() 事件,实现前进功能
private void goforwd_Click(object sender, EventArgs e)
{
webView21.GoForward();
}
复制代码
窗体设计器中选中地址栏,在事件属性面板,双击keyDown,实现按回车键时打开输入的网址
private void address_KeyDown_1(object sender, KeyEventArgs e)
{
String url = address.Text;
if (e.KeyCode == Keys.Enter && url.Length > 0)
{
if (!url.StartsWith("http"))
{
url = "http://" + url;
}
webView21.CoreWebView2.Navigate(url);
}
}
复制代码
双击 go 按钮,绑定打开网址,如果不存在http,则自动添加。实际同keyDown 事件一致
private void go_Click(object sender, EventArgs e)
{
String url = address.Text;
if (url.Length > 0)
{
if (!url.StartsWith("http"))
{
url = "http://" + url;
}
webView21.CoreWebView2.Navigate(url);
}
}
复制代码
当页面加载完毕后,需要判断是否可前进和后退,据此禁用或启用 后退、前进 按钮, 属性 CanGoBack CanGoForward 可判断,当不可执行时,禁用相应按钮
void EndNav(object sender, CoreWebView2NavigationCompletedEventArgs args){
this.goback.Enabled = webView21.CanGoBack ? true : false;
this.goforwd.Enabled = webView21.CanGoForward ? true : false;
}
复制代码
将此方法在 Form1 构造方法中绑定 webView21.NavigationCompleted += EndNav;
3. 强制所有页面均在这一个窗口中显示,即取消 "target='_blank'" 的打开新窗口
设计器中选中 webview21,在属性窗口的 CoreWebView2InitializationCompleted
上双击,添加代码,绑定NewWindowRequested 事件
// 禁止新窗口
private void webView21_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) {
webView21.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
}
复制代码
禁止代码在 CoreWebView2_NewWindowRequested
方法中实现
private void CoreWebView2_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e)
{
String url = e.Uri.ToString();
if (!url.Contains("oauth"))
{
webView21.Source = new Uri(url);
e.Handled = true;//禁止弹窗
}
}
复制代码
在此需做个简单判断,如果 url中含有 oauth
字符,一般多是oauth授权登录窗口,比如微信登录等,此时允许在新窗口中弹出,否则登录会存在问题
4. 根据窗口尺寸变化,自动调整页面显示
在Form1 的构造方法中,添加
this.Resize += new System.EventHandler(this.Form1_Resize);
private void Form1_Resize(object sender, EventArgs e){
webView21.Size = this.ClientSize - new System.Drawing.Size(webView21.Location);
go.Left = this.ClientSize.Width - go.Width;
address.Width = go.Left - address.Left;
}
复制代码
4. 集成 webview2runtime
msdn文档上 developer.microsoft.com/zh-cn/micro… 有2种集成方法
一是 引导安装,优点是打包后的程序由于无需集成运行时,尺寸较小,但缺点是第一次打开时需要联机下载并安装,比较耗时
二是直接 独立安装程序,第一次打开时,检测到电脑上不存在runtime,则直接执行安装,优点是相对较快点,但缺点也很明显,安装包非常大。
判断计算机环境中是否已存在 webview2runtime
public static bool IsInstallWebview2()
{
string? res = "";
try
{
res = CoreWebView2Environment.GetAvailableBrowserVersionString();
}
catch (System.Exception)
{
}
if (res == "" || res == null)
{
return false;
}
return true;
}
public static void InstallWebview2Async()
{
if (!IsInstallWebview2())
{
Form1.Gui.Text = "第一次使用需要初始化,将耗费一点时间,请耐心等待完成";
Form1.Gui.Size = new System.Drawing.Size(800, 50);
Form1.Gui.MaximizeBox = false;
string MicrosoftEdgeWebview2Setup = System.IO.Path.Combine(Application.StartupPath, "MicrosoftEdgeWebView2RuntimeInstallerX64.exe");
Process.Start(MicrosoftEdgeWebview2Setup, " /silent /install").WaitForExit();
if (IsInstallWebview2())
{
//重启
Application.Restart();
Process.GetCurrentProcess()?.Kill();
}
}
}
复制代码
在Form1构造方法中,起一个 Task 异步任务,进行检测并安装。至于为什么单起一个 task,因为这个比较耗时,如果在同一个线程中进行,会出现一段时间的卡死,让人不爽。
Task.Run(() => InstallCheck.InstallWebview2Async());
复制代码
5. 打包
vs菜单-生成-打包,然后从 developer.microsoft.com/zh-cn/micro… 下载独立安装包,并放在打包后的exe同目录下,即可
Form1.cs 源码
using Microsoft.Web.WebView2.Core;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace webview2
{
public partial class Form1 : Form
{
public static Form Gui;
public Form1()
{
Gui = this;
InitializeComponent();
// 调整尺寸
this.Resize += new System.EventHandler(this.Form1_Resize);
// 更改窗口标题
webView21.NavigationStarting += EnsureHttps;
//启用或禁用前进 后退按钮
webView21.NavigationCompleted += EndNav;
//检测并自动安装 webview2runtime
Task.Run(() => InstallCheck.InstallWebview2Async());
}
//导航结束
void EndNav(object sender, CoreWebView2NavigationCompletedEventArgs args)
{
this.goback.Enabled = webView21.CanGoBack ? true : false;
this.goforwd.Enabled = webView21.CanGoForward ? true : false;
}
//导航开始
void EnsureHttps(object sender, CoreWebView2NavigationStartingEventArgs args)
{
String uri = args.Uri;
address.Text = uri;
Form1.ActiveForm.Text = webView21.CoreWebView2.DocumentTitle.Length > 1 ? webView21.CoreWebView2.DocumentTitle : this.Text;
}
// 窗体尺寸变化
private void Form1_Resize(object sender, EventArgs e)
{
webView21.Size = this.ClientSize - new System.Drawing.Size(webView21.Location);
go.Left = this.ClientSize.Width - go.Width;
address.Width = go.Left - address.Left;
}
// 禁止新窗口
private void CoreWebView2_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e)
{
String url = e.Uri.ToString();
if (!url.Contains("oauth"))
{
webView21.Source = new Uri(url);
e.Handled = true;//禁止弹窗
}
}
// 禁止新窗口
private void webView21_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
webView21.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
}
// go按钮
private void go_Click(object sender, EventArgs e)
{
String url = address.Text;
if (url.Length > 0)
{
if (!url.StartsWith("http"))
{
url = "http://" + url;
}
webView21.CoreWebView2.Navigate(url);
}
}
//地址栏回车
private void address_KeyDown_1(object sender, KeyEventArgs e)
{
//MessageBox.Show(e.KeyCode.ToString(), "bb");
String url = address.Text;
if (e.KeyCode == Keys.Enter && url.Length > 0)
{
if (!url.StartsWith("http"))
{
url = "http://" + url;
}
webView21.CoreWebView2.Navigate(url);
}
}
// 后退
private void goback_Click(object sender, EventArgs e)
{
webView21.GoBack();
}
//前进
private void goforwd_Click(object sender, EventArgs e)
{
webView21.GoForward();
}
}
// 检测webview2runtime 工具类
public static class InstallCheck
{
public static bool IsInstallWebview2()
{
string? res = "";
try
{
res = CoreWebView2Environment.GetAvailableBrowserVersionString();
}
catch (System.Exception)
{
}
if (res == "" || res == null)
{
return false;
}
return true;
}
public static void InstallWebview2Async()
{
if (!IsInstallWebview2())
{
Form1.Gui.Text = "第一次使用需要初始化,将耗费一点时间,请耐心等待完成";
Form1.Gui.Size = new System.Drawing.Size(800, 50);
Form1.Gui.MaximizeBox = false;
string MicrosoftEdgeWebview2Setup = System.IO.Path.Combine(Application.StartupPath, "MicrosoftEdgeWebView2RuntimeInstallerX64.exe");
Process.Start(MicrosoftEdgeWebview2Setup, " /silent /install").WaitForExit();
if (IsInstallWebview2())
{
//重启
Application.Restart();
Process.GetCurrentProcess()?.Kill();
}
}
}
}
}
复制代码
参考资料
- 下载 webview2 developer.microsoft.com/zh-cn/micro…
- 分发webveiw2runtime方式 docs.microsoft.com/zh-cn/micro…
- webview2 文档 docs.microsoft.com/zh-cn/micro…