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

关于QCefView的一些事

不知不觉QCefView这个项目已经诞生7年多了,自从开源这个项目之后我也没有做过相关的介绍和宣传。这些年我通过业余时间不断优化重构,修复缺陷,扩展项目的支持边界,从最初只能在Windows平台上基于Qt框架开发应用的单一场景,扩展成了跨桌面端操作系统(Windows/macOS/Linux)多框架多语言绑定(Qt/C++,Cocoa/OC++,.NET/C#)的CefView项目栈。期间也有不少热心的朋友积极地通过各种方式来提供contribution,这里一并致谢。今天写篇文章回顾一下CefView项目栈是如何诞生和发展到现在的状态,以及将来会有什么样的规划。

QCefView的诞生

QCefView诞生于2015年9月,当时我还在一家游戏平台公司工作,负责重写公司的起家产品——游戏平台+即时通讯的混合体。立项的时候考虑过使用web技术来开发,但是因为当年在QQ工作的时候对于性能关注深入骨髓,所以我极力反对使用web技术来做一个IM产品(现在回头来看,海外的IM产品几乎清一色都是用electron开发的了,slack/teams/lark等,不过在15年的时候electron也并不是那么成熟,而且现在也还是非常臃肿)。后来我们确定不使用web技术来开发,而是继续使用Qt来当作UI库,不过当时我约定Qt的使用仅限于当作UI组件,只能在UI相关的模块里使用必要的Qt基础组件,UI之外的所有模块都不能使用Qt相关的资源。从架构设计和技术实现的角度来说,这个产品无论是功能,架构还是项目代码质量,对比现在的很多桌面端Client产品都还是十分优秀和先进的。IM功能几乎对标了QQ的所有功能,气泡,表情,文件传输,消息记录,语音聊天,截图,群消息。

游戏大厅/IM合并模式


游戏大厅/IM分离模式

这个产品中的两个核心模块是游戏平台和IM,IM部分的UI全部使用Qt实现,游戏大厅部分最初的UI也是通过Qt实现,实现方案我前后更换了好几版,从第一版的QWidget,到QTabWidget再到最后的QGraphicsView。在这个过程中我已经感到这种Native的做法对于后期运营来说成本会非常高。要么运营妥协,不会经常改变UI布局,要么开发妥协改布局就发版本。这种内容型平台产品本身就具有强运营属性,无论谁妥协,最终结果对团队来说好像都不太能接受,所以最后领导说要不还是用web来做吧。客观地说,游戏大厅就是一个内容展示的窗口,用户的交互并不会像IM消息窗口一样频繁复杂,所以我也觉得是可行的。然后我就花了两周的时间把CEF封装成了一个基于QWidget的控件,当时叫做GxxCefView,这就是现在的QCefView的雏形。

在这之前我也没有了解过libcef,网上也没找到类似的方案,所以第一版GxxCefView就用了最原始的Embedded Alien Window的方法。最初的GxxCefView的功能其实比现在的QCefView要多一些,比如自定义schema handler,通过web前端访问特定的schema的URL即可向Native C++代码进行消息传递(这个方法在后来QCefView的迭代中已已经去除了,因为需要用户来实现自己自定义的schema handler,比较麻烦)。当然最初的版本在架构上没有现在的QCefView清晰简洁,毕竟是赶时间做出来的。不过有一点到现在都没有改变,那就是——“封装”。GxxCefView创建之初的一个最重要的原则就是把CEF相关的所有API和逻辑都封装起来,只对外暴露一个干净的继承自QWidget的组件,使用者不必知道CEF内部如何工作,只需要按照QWidget来使用就可以开发基于Web的混合应用。前段时间有个朋友提交了一个PR,需要暴露大量CEF的头文件,我跟他解释了这个原则,最终也没有merge这个PR。

QCefView的重生

2016之后,我在业余时间抽空按照当时的需求重新设计了架构,然后慢慢地把代码全部重写了一遍,取名QCefView发布到了GitHub (tishion/QCefView),这就是QCefView的第一个开源版本。发布之后零零散散的收到一些issue和PR,很奇怪的是issue和PR大多来自海外用户。接下来的几年QCefView几乎没有太大的改进,都是在进行一些边边角角的修改,这个版本的QCefView只支持子窗口模式,对于off screen rendering我也没有合适的动力和动机去实现。在这期间有个UK的开发者(BenHetherington (Ben Hetherington) (http://github.com))基于QCefView做了大量的改进,但是他并没有发起PR,而是另一个开发者发起的PR中包含了他的大量修改。

后面的时间,我又抽空用同样的思路实现了CocoaCefView这个项目,把CEF封装在一个继承自NSView的控件中,实现了在macOS系统上无差别应用CEF的方案,只是完成后觉得没什么意义,因为并没有实际应用场景。直到2020年,工作需要,又是做平台型产品,而且是典型的基于内容的平台型产品,首发macOS。由于人少,项目时间非常紧迫,所以我毫不犹豫的把CocoaCefView拿出来用了,我也趁这个机会实战了一下web前端开发,花了一个周,用Vue+Vuetify实现了一个SPA。


START macOS版

后来项目顺利上线,我的业余时间也没有那么多了,周末都要做客服收集用户问题,解决疑难杂症。不过我还是挤出了时间重新思考了一下QCefView和CocoaCefView的架构设计问题,然后就抽取出了CefViewCore这个框架无关的核心层,然后CefView的项目栈就变成现在这个样子:


CefView 项目栈

CefViewCore作为一个对CEF的核心封装,与框架无关,只是封装实现了让CEF运行起来的必要逻辑,打包CEF所需要的资源/二进制文件等。基于CefViewCore实现了:

  1. 用于Qt框架的QCefView,支Windows/macOS/Linux
  2. 用于Cocoa框架的CocoaCefView

经过这次重构,QCefView已经不是单独的一个项目了,而是CefView这个组织下的一个项目,之前的QCefView被我封存起来,不再维护了。2020年底,同样因为要上线Windows端(12月中旬定下的目标春节1.11上线,大厅部分0代码),所以又是之前的套路走一遍,前端App直接复用,节省了大量开发时间,顺利上线。

START Windows版

2021年身体不适,所以休息了一段时间,闲来无事的时候终于静下心来把off screen rendering实现了,至此CefView项目的结构就稳定下来了。

目前的CefView项目栈

在这之后我也通过一些渠道了解到QCefView其实是已经被一些小的公司或者个人使用的,只是没有人会知会我一下,这其中也不乏商业盈利能力很强的一些公司。当然也有一些GitHub上的开发者,直接把QCefView的代码拿去改改名字,就用在了自己的项目中,而且做很多宣传,这样我就不能好好说话了。

QCefView的未来规划

最近对QCefView的未来路线多了一些想法,因为CEF在游戏引擎里面也是不可或缺的重要组件,所以这一块也是可以做集成的,比如Unity里面的ZFBrowser其实做的已经相当好了。还有最近收到一个Godot引擎用户,希望我能帮忙实现一个用于Godot引擎定的跨平台的CEF插件,这个请求有点悬,我果断拒绝了。上周刚刚实现了CefView的.NET平台的封装,并且能在WPF环境中正常使用了:

CefView.WPF

如果要集成到游戏引擎,目前的架构还是要做大的调整的,因为游戏引擎的运行时过于复杂,所以CefView并不适合做侵入式的引用,而应该改成彻底的独立进程方案,然后通过IPC与引擎内部的Proxy通信,保证引入最小的改动和影响,从而保证稳定性。我已经实现了一个侵入式引用的Unity Demo,但是效果不理想,所以就不再继续了。罗列一下,未来可以支持的框架:

  1. 基于Unity的封装
  2. 基于Unreal的封装
  3. 基于Godot的封装
  4. 基于MAUI的封装(微软在2021年的时候发布了基于edge内核的WebView2,当然edge也是基于CEF的,并且在MAUI中可用,不过不支持跨平台)

但也只是在这罗列一下,并不一定会去实现,也许有感兴趣的朋友可以尝试来实现一下。

写在最后

可以做的很多,但是时间却不是那么多,毕竟是始于兴趣的一个项目,从发布第一天也没有想过要从这个项目上得到什么。所以我也不会保证能够持续和及时的投入,因为我还有工作要做。CefView也并不是一个很有技术含量的项目,只是对libcef做了一些简单的封装,一些提升效率的工程化改进,以及一些开源项目标准的实施。

这只是我的技术工具箱里面平平无奇的一个项目,以后会继续从我的垃圾堆里翻些东西出来分享。

传送到GitHub:CefView (github.com)

相关文章:

  • b站pink老师JavaScript的jQuery 案例代码——电梯导航案例
  • Python快速实现简易飞机大战小游戏
  • PowerWorld仿真与电力系统潮流计算(牛顿拉夫逊法和高斯赛德尔法)(Matlab实现)
  • VSCode自动更新后关闭,重新打开后版本自动降级
  • Google Earth Engine(GEE)——如何处理阈值筛选后的结果没发生变化,以青藏高原NDBI为例
  • 数字验证学习笔记——SystemVerilog芯片验证4 ——数据类型
  • 行为树BT设计与实现
  • 基于神经网络的指纹识别,指纹比对技术何时出现
  • 【图像分割】基于差分进化算法优化模糊熵实现多级图像阈值分割附matlab代码
  • LeetCode 0817. 链表组件
  • 27、Java——超市会员管理系统(对象+IO流)
  • 嵌入式分享合集74
  • 布尔模型,向量空间模型
  • 详解数商云采购协同系统供应商准入流程,加强汽修供应商管理革新企业采购渠道
  • 基于JAVA医护人员排班系统计算机毕业设计源码+系统+lw文档+部署(2)
  • 2017-09-12 前端日报
  • Docker容器管理
  • HTML-表单
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • React-redux的原理以及使用
  • SpringBoot 实战 (三) | 配置文件详解
  • Vue2.x学习三:事件处理生命周期钩子
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 使用common-codec进行md5加密
  • python最赚钱的4个方向,你最心动的是哪个?
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • ​虚拟化系列介绍(十)
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (C#)一个最简单的链表类
  • (阿里云万网)-域名注册购买实名流程
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (南京观海微电子)——COF介绍
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • . NET自动找可写目录
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .NET delegate 委托 、 Event 事件
  • .NET Framework 4.6.2改进了WPF和安全性
  • .Net 代码性能 - (1)
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • @RunWith注解作用
  • @我的前任是个极品 微博分析
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [1] 平面(Plane)图形的生成算法
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • [AS3]URLLoader+URLRequest+JPGEncoder实现BitmapData图片数据保存
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)
  • [C++] cout、wcout无法正常输出中文字符问题的深入调查(1):各种编译器测试
  • [C++]:for循环for(int num : nums)
  • [CVPR 2023:3D Gaussian Splatting:实时的神经场渲染]
  • [Enterprise Library]调用Enterprise Library时出现的错误事件之关闭办法