使用C# CEFSharp在WPF中开发桌面程序实现同一网站多开功能

在网络商业运营领域,同时运营多个淘宝店铺的现象屡见不鲜。为了满足这一需求,实现同一网址的多开功能变得尤为关键。这一需求虽然实用,但实现起来却面临诸多挑战。在这个过程中,技术人员们也经历了不少喜怒哀乐。

开发经历回顾

阿峰,今年44岁,是个久未涉足桌面软件开发的程序员。自2018年那次经历后,他最近又接手了一个WPF项目,任务是实现网址的多开功能。回想起那时候,从接到任务的那一刻起,他就感受到了满满的未知和挑战。一开始,看到官方提供的示例,他以为成功在望,因为示例中不同网站可以互不干扰。然而,实际操作起来,问题却一个接一个。

开发这一过程,会遇到不少代码难题。由于缺乏相关经验,诸多事项需从头开始探索。在搜集资料、修正代码的过程中,时间悄然流逝,精力也在持续消耗。

搜索与趟坑

初次搜索解决方案时,搜索结果呈现了答案,但当时并未意识到这些信息的价值。经过一番曲折,才意识到先前忽略的部分才是最珍贵的。在探索过程中,不断跨越一个又一个代码难题。有时是逻辑上的错误,有时是语法上的小疏忽,这些错误耗费了我大量时间去排查。

每次以为找到了对策,结果操作时却问题频发,挫败感不断累积。于是,我调整心态,重新寻找出错的地方,反复尝试各种可能性。

关键实现

直接引入了必要的核心代码。代码页面涵盖了点击切换浏览器代码以及主程序启动时的初始化代码等。每一行代码都凝聚了多次试验的成果。编写这些代码时,必须保证各项功能的正常运作,并持续检验其稳定性。

cs 复制代码
/// 

        /// 初始化浏览器集合
        /// 

        public void InitDictionary()
        {
            foreach (ChatUser user in LocalAccount)
            {
                if (!Dict.ContainsKey(user.id))
                {
                    #region 初始化ChromiumWebBrowser
                    string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cache\Cache_" + user.id.ToString());
                    if (!Directory.Exists(path))
                        Directory.CreateDirectory(path);
                    var setting = new RequestContextSettings()
                    {
                        CachePath = path,
                        PersistSessionCookies = true,
                        PersistUserPreferences = true
                    };
                    var context = new RequestContext(setting);
                    var cookieManager = context.GetCookieManager(null);
                    //这样设置的cookie不是全局的,只有当前browser才能访问
                    cookieManager.SetCookie("dxl.cn", new Cookie
                    {
                        Name = $"cookie{user.nickname}",
                        Value = $"cookievalue{user.nickname}",
                        Path = path
                    });
                    ChromiumWebBrowser chromeBrowser = new ChromiumWebBrowser()
                    {
                        Address = config.AppSettings.Settings["ChatUrl"].Value,
                        RequestContext = context,
                        MenuHandler = new NullMenuHandler(),
                        LifeSpanHandler = new LifeSpanHandler(),
                        Visibility = Visibility.Hidden
                    };
                    chromeBrowser.JavascriptObjectRepository.Settings.LegacyBindingEnabled = true;
                    chromeBrowser.JavascriptObjectRepository.Register("bound", obj, false);
                    #endregion
                    obj.WebBrowserCallback += Obj_WebBrowserCallback;
                    user.msgNum = null;
                    chromeBrowser.LoadUrl(config.AppSettings.Settings["ChatUrl"].Value.Replace("login", "sso") + $"?token={user.token}");
                    Dict.Add(user.id, chromeBrowser);
                    mainWindow.MainGrid.Children.Add(chromeBrowser);
                }
            }
            AccountCountText = $"{LocalAccount.Count}/{config.AppSettings.Settings["MaxAccountCount"].Value}";
            if (AccountPlusVisibility != Visibility.Visible)
            {
                AccountPlusVisibility = Visibility.Hidden;
            }
        }

精心编排代码逻辑,努力优化代码架构,目的都是为了使程序运行得更加出色。即便如此,即便在取得一定进展后,仍然面临着更多挑战。

cs 复制代码
<Border Grid.Row="1" BorderBrush="Transparent" Background="#f0f0f0" BorderThickness="0" >
<Grid x:Name="MainGrid"/>
            

优化程序

WPF的数据驱动挺受欢迎,而且对高DPI设备的支持也不错。但最初打包后的文件有300多兆,老板对此难以接受。于是开始了漫长的优化过程。经过不懈努力,文件大小被压缩到了100兆以下。在这一过程中,我们不断尝试新的方法,对程序进行了精简。

cs 复制代码
MainGrid就是多个ChromeBrowser的父容器,在切换账户的使用显示当前账户对应的ChromeBrowser其他的隐藏。
cs 复制代码
public void ChangeBrowser(object xaml_obj)
        {
            var array = xaml_obj as object[];
            if (array != null && array.Length == 2)
            {
                Grid mainGrid = array[0] as Grid;
                ChatUser user = array[1] as ChatUser;
                if (user != null)
                {
                    CurrentBrowser = Dict[user.id];
                    foreach (var chromeBrowser in mainGrid.Children)
                    {
                        if (chromeBrowser == CurrentBrowser)
                        {
                            ((ChromiumWebBrowser)chromeBrowser).Visibility = Visibility.Visible;
                        }
                        else
                        {
                            ((ChromiumWebBrowser)chromeBrowser).Visibility = Visibility.Hidden;
                        }
                    }
                }
            }
        }
cs 复制代码
  /// 

        /// Cef 参数
        /// 

        /// 
        public static CefSettings GetCefSettings()
        {
            var settings = new CefSettings
            {
                Locale = "zh-CN",
                AcceptLanguageList = "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
                RemoteDebuggingPort = 8088,
                LogSeverity = LogSeverity.Disable,
                PersistSessionCookies = true,//Persistent Cookies会被保存在一个浏览器的一个子文件夹中
                UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
                IgnoreCertificateErrors = true,
                MultiThreadedMessageLoop = true,//让浏览器的消息循环在一个单独的线程中执行,建议设置成true,具体含义看看浏览器消息处理。
                WindowlessRenderingEnabled = true,//如果不开启好多用那种JSUI的控件的网站 都有问题
                CachePath = AppDomain.CurrentDomain.BaseDirectory + "/Cache",//缓存目录
            };
            settings.CefCommandLineArgs.Add("disable-application-cache", "1");//不要缓存
            settings.CefCommandLineArgs.Add("disable-gpu", "1");//去掉gpu,否则chrome显示有问题
            settings.CefCommandLineArgs.Add("enable-media-stream", "1"); //Enable WebRTC
            settings.CefCommandLineArgs.Add("proxy-auto-detect", "0");
            settings.CefCommandLineArgs.Add("no-proxy-server", "1");
            settings.CefCommandLineArgs.Add("allow-running-insecure-content", "1");
            //settings.CefCommandLineArgs.Add("ppapi-flash-version", "34.0.0.118"); //设置flash插件版本
            //string flashFilePath = Application.StartupPath + @"Pluginspepflashplayer.dll";
            //settings.CefCommandLineArgs.Add("ppapi-flash-path", flashFilePath);
            //settings.CefCommandLineArgs.Add("enable-system-flash", "1");
            settings.CefCommandLineArgs.Add("enable-npapi", "1");
            settings.CefCommandLineArgs.Add("ppapi-out-of-process", "1");
            settings.CefCommandLineArgs.Add("plugin-policy", "allow");

            return settings;
        }
相关推荐
数据小小爬虫8 分钟前
利用Java爬虫获取义乌购店铺所有商品列表:技术探索与实践
java·开发语言·爬虫
NoneCoder34 分钟前
JavaScript系列(24)--内存管理机制详解
开发语言·javascript·ecmascript
Pafey36 分钟前
c++ 中的容器 vector、deque 和 list 的区别
开发语言·c++
ShyTan1 小时前
java项目启动时,执行某方法
java·开发语言
甄同学1 小时前
【WPS】【WORD&WORD】【JavaScript】实现微软WORD自动更正的效果
开发语言·前端·javascript
Quantum&Coder1 小时前
Swift语言的数据库编程
开发语言·后端·golang
YYHYJX1 小时前
C#学习笔记 --- 简单应用
开发语言·学习·c#
Clockwiseee1 小时前
JAVA多线程学习
java·开发语言·学习
Nobita Chen1 小时前
Python实现windows自动关机
开发语言·windows·python
码路刺客1 小时前
一学就废|Python基础碎片,OS模块
开发语言·python