基于webview2定制一个没什么卵用的浏览器

原想编译 chromium 定制个浏览器,结果搞半天发现真不是一般的费劲啊,算啦,额们这菜鸟,还是直接套个Microsoft 家的 Webview2 吧,又简单又快捷,加个外壳改改皮肤就行了,虽然并没什么卵用☺☺☺☺。

最终效果

image.png

image.png

具体实现步骤

1. winform 搭个外壳并添加webview2组件

打开 visual studio 2019,新建一个 c# 的 windows窗体应用
image.png


工具-NuGet包管理-搜索安装 webview2,加入项目,安装 image.png


返回窗体设计器-WebView2-拖动winforms的webview2控件到窗体中合适位置,name=webView21 image.png

设置窗体属性-Source,即打开浏览器默认的网址,比如我这里设置的是 juejin


2. 添加 后退 前进 地址栏 go 等按钮

添加3个button控件,分别是 后退按钮、前进按、go按钮和地址栏 image.png

双击 后退按钮,绑定 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();
                }
            }
        }
    }
}

复制代码

参考资料

  1. 下载 webview2 developer.microsoft.com/zh-cn/micro…
  2. 分发webveiw2runtime方式 docs.microsoft.com/zh-cn/micro…
  3. webview2 文档 docs.microsoft.com/zh-cn/micro…

猜你喜欢

转载自juejin.im/post/7061883110463373343