十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Delphi 12.3下用CEF4Delphi彻底告别IE内核控件问题

Delphi 12.3下用CEF4Delphi彻底告别IE内核控件问题 简介本资源是面向Delphi开发者尤其适配Delphi 12.3版本的CEF4Delphi开源控件完整工程包用于在Delphi应用中嵌入Chromium浏览器内核实现高性能Web界面集成、混合开发与本地Web应用托管。资源包含2000个文件主体为420个Pascal源码.pas、92个Delphi项目文件.dpr、81个窗体描述.dfm及934个HTML前端资源辅以批量清理脚本.bat、部署配置.deployproj和跨平台支持文件.fmx/.lpi总大小11.63MB结构完整覆盖编译、调试、部署全流程。已有63人学习下载包内含多套示例工程、详细文档CHM/HTML、图标与资源文件.ico/.res/.png以及一键清理DCU的实用批处理脚本便于快速上手、二次开发与环境适配。 上个月做老项目维护客户甩过来一张截图内部OA系统在浏览器里加载一个旧的上传组件时直接弹窗提示“不能装载NTKO大文件上传控件请确保使用IE浏览器并检查浏览器的安全设置”。截图背后是一排无辜的“控件加载失败”。我当时的第一反应是又得把IE兼容模式那套流程走一遍了。后来我干脆把公司几个历史项目里所有基于TWebBrowser的界面全部换成了CEF4Delphi这个在Delphi 12.3下使用的Chromium嵌入控件库一次性解决了内核老旧、样式错乱、JS新特性不兼容的问题。如果你现在也在用Delphi 12.3手里恰好攥着一份CEF4Delphi-master.zip却不知道从哪下手这篇是我完整走过的流程从解压到编译、从第一个浏览器窗体到生产发布全部捋一遍。1. 从“IE 不能装 ActiveX 控件”聊起为什么我在 Delphi 12.3 里必须换内核1.1 那些年我们被 IE 内核控件坑过的项目很多老系统至今还在用TWebBrowser说白了就是包装了一个IE内核也就是ActiveX那套东西。问题在于IE内核从IE9之后基本不更新了。HTML5规范里那些新特性例如CSS Grid布局、flex弹性盒子、WebSocket在IE上都跑不顺畅。很多单位内部系统还停留在“只能在IE下打开”的状态一到Chrome或者Edge就卡死、白屏、按钮错位。更麻烦的是新出现的各种安全控件、加密组件都是围绕着现代浏览器开发的比如常见的CA安全控件、银行UKey登录、电子签章插件它们默认支持Chrome内核对IE反而爱搭不理。而老的ActiveX控件例如NTKO大文件上传、Formula One表格、LODOP打印控件又只认IE。这就形成了一个两头挨骂的尴尬局面一边是老控件彻底迁移不走另一边是用户已经默认用Chrome你非让人家切回IE模式人家直接一句“你们的系统也太老了”甩回来。说句实在话我做了这么多年Delphi开发在嵌入浏览器的选型上以前真的没什么好选。VCL自带的TWebBrowser只是浅浅一层包装连事件都要自己补更别谈多进程隔离了。程序里只要一个页面脚本写死循环整个UI就冻住用户只能强杀进程。Debug起来叫天天不应。后来接触了CEFChromium Embedded Framework才算找到了治本的办法。1.2 CEF4Delphi 到底是什么它解决了哪些问题CEF4Delphi字面拆开就是“CEF for Delphi”是CEF的Delphi语言绑定库。它把谷歌Chromium浏览器内核封装成一套可以在Delphi中直接使用、以VCL/Lazarus组件形式呈现的控件集。你在GitHub上看到的CEF4Delphi-master.zip就是它的主分支源码包。它的核心解决思路很简单浏览器内核不再依赖操作系统自带的IE组件而是把Chromium浏览器引擎整个打包进你的程序目录。这样你程序里那个嵌入页面无论在什么Windows版本、什么系统环境下渲染效果都是一模一样的和IE的版本、系统的补丁更新没有半点关系。对于做客户端程序的公司来说这是非常关键的一点用户不在IE9的机器上看到的界面和你在开发机Chrome上看到的界面可以有细微差别但在CEF4Delphi里不会出现这种随系统环境漂移的诡异表现。我特别欣赏的是它还支持多进程架构。Chromium本身就分成浏览器主进程、渲染器进程、GPU进程等多个进程CEF4Delphi把这个机制也保留了下来。某个页面脚本崩溃顶多是一个渲染进程挂掉重新加载一下就好不会再把你的整个主程序拖死。这一点对长期运行的工控、收银、MIS类软件尤其重要。从Delphi 12.3的角度来说CEF4Delphi的master分支已经对现在的新版编译器做了完整适配代码里那些动态绑定、接口引用计数、匿名方法的部分都能在新编译环境下顺利编译。相比以前某个老版本需要你自己打补丁才能通过Windows SDK头文件对齐现在的版本可以说开箱即用。就算编译时遇到什么问题也基本都是环境路径的配置问题一会儿我会挨个讲。1.3 我不推荐 Edge WebView2 的理由在 Delphi 12.3 场景下我知道肯定有人要问微软不是有WebView2吗基于Edge内核也是不断更新的Chromium为什么不用它我说一下我的理由供你参考。WebView2的官方支持方式偏向C/.NET虽然Delphi下也有人写了封装但生态和资料比CEF4Delphi还是少了一大截。CEF4Delphi在Delphi圈子里已经活跃了很多年遇到问题在质量论坛、Stack Overflow上都能搜到对应方案。更重要的一点是WebView2依赖的是系统级的Edge运行时用户机器上如果没有装或者版本过旧你还是得想办法分发运行时。而CEF4Delphi是把libcef.dll、资源文件整个打包给你程序目录里放什么版本运行起来就一定是这个版本版本锁定非常彻底不会出现“用户那边WebView2又偷偷更新了结果行为变了”的情况。另外CEF4Delphi对自定义协议的注册支持、对JS-Delphi双向调用的灵活度也要明显好于WebView2的封装层。如果你需要和硬件设备通信、调用本地DLL、通过自定义scheme加载本地页面CEF4Delphi的灵活性会让你舒服得多。所以从嵌入浏览器的技术选型上我坚定站在了CEF4Delphi这一边。2. 解压 master.zip 之后的第一件事认识目录结构和二进制依赖2.1 CEF4Delphi 源码目录里都有什么把CEF4Delphi-master.zip解压后你首先会看到一堆目录。第一次接触的人很容易懵不知道哪些该用、哪些是干嘛的。我按我实际用到的顺序列一个快速索引。source这是核心源码目录里面有个cef3子目录存放着所有CEF的Delphi封装类编译时搜索路径必须包含这层。demos官方示例程序里面有多个示例项目。刚上手时建议直接打开一个最简单、不依赖第三方组件的demo跑通比从零建工程省事得多。resourcesChromium运行需要的资源文件包括各种pak文件、icu数据文件发布时要一起拷走。patches一些针对CEF二进制文件的补丁说明通常没用到除非你自己编译CEF二进制。packages如果你要安装设计时包这个目录里能找到对应的Delphi工程文件编译后能让TChromium、TChromiumWindow出现在IDE组件面板里。我自己实际开发时的用法是不安装设计时包直接把source目录加进工程的搜索路径然后在运行时用代码动态创建TChromium。这样整个工程结构更干净IDE也不会因为频繁安装控件包而出现“组件版本冲突”“IDE启动后控件丢失”之类的幺蛾子。当然如果你喜欢在窗体设计器里拖拽组件、在Object Inspector里设属性那还是把设计时包装上更舒服。两种方式不影响运行时行为选一个顺手就好。2.2 最容易被忽略的二进制组件目录以前碰到不少朋友把CEF4Delphi源码编译得标标准准可是运行起来就是白屏、闪退甚至提示找不到libcef.dll。问题十有八九出在CEF4Delphi仓库并不自带CEF的二进制文件。你下载的CEF4Delphi-master.zip里只有Delphi封装源码真正干活的不是这些源码而是CEF官方发行的那一堆DLL和资源文件。对应的做法是从CEF4Delphi的GitHub发布页面找到与你下载的master版本匹配的CEF二进制包通常发布说明里会给一个下载链接。解压后你会看到这样一些东西libcef.dll核心浏览器引擎libEGL.dll、libGLESv2.dll图形渲染相关icudtl.datICU国际化数据文件resources目录包含chrome_100_percent.pak等资源文件locales目录各语言包snapshot_blob.bin、v8_context_snapshot.binV8脚本引擎快照文件发布时这些东西一个都不能少而且必须放在一起通常直接放到你的程序EXE同目录下。折腾的时候可以先把整个二进制包解压到你项目的输出目录然后再逐个精简。在Delphi 12.3下特别要注意目标平台是Win32还是Win64。CEF二进制包分32位和64位你编译Delphi工程时选了哪个平台就要放对应位数的DLL。我见过有人Win64的exe配了32位的libcef.dll结果一启动就弹出“应用程序无法正常启动”点了确定程序直接消失非常容易踩。2.3 Delphi 12.3 的版本适配与编译顺序如果你从GitHub拉到的master分支不是最新或者官方发布说明里还没写支持Delphi 12.3也别太担心。CEF4Delphi对新版编译器的兼容速度一直挺快的一般差距不会太大。遇到编译报错先把错误信息贴到CEF4Delphi的Issues里搜一下大多数情况是某个包注册失败、或者个别单元引用了旧版RTL不存在的符号。编译的推荐顺序是先把source\cef3目录里的所有.pas文件过一遍核心编译也就是打开一个官方demo工程CtrlF9编译看是否通过。如果你要装设计时包才需要去packages目录编译运行时包、再编译设计时包并安装。编译通过后把CEF二进制文件复制到demo的输出目录运行起来能看到页面加载就是一个完整的“hello world”。这里有个容易搞混的点Delphi 12.3的Platform默认有时候会是Win32但你的代码和项目可能因为某些第三方库只发64位导致你切到Win64才发现库路径里的DCU是32位编出来的。DCU是不区分位数的也不会自动重新编译经常会报“Unit X was compiled with a different version of Y”之类的错误。解决办法就是把source\cef3加进工程的搜索路径时同时留意IDE右下角的电脑设备标记是否正确选中了目标平台再把所有历史DCU清一遍让编译器重新生成对应平台的DCU。多花两分钟能省一个小时的排查时间。3. 把 CEF4Delphi 装进 Delphi 12.3库路径、设计时包和第一个浏览器窗体3.1 设置全局库路径还是只在工程里引用给Delphi工程添加CEF4Delphi源码引用有两种做法一种是在“Tools Options Delphi Options Library”里把source\cef3加进全局库路径这样任何新工程都能直接继承另一种是在特定工程的“Project Options Delphi Compiler Search path”里加。我建议对CEF4Delphi这种长期要用的库直接加到全局库路径里省得每个工程都重复配一遍。但全局库路径也有个副作用IDE在打开某些老工程时如果老工程引用了另一个版本的CEF4Delphi就会因为搜索路径里先找到了新版DCU而出问题。为了避免这种“控件版本问题导致每次进入IDE都丢失控件”的情况我的经验是能用工程级搜索路径就用工程级除非所有项目已经统一升级到同一个CEF4Delphi版本。项目里的.dproj文件里记录的是相对路径还是绝对路径也直接影响换机器后能不能顺利打开我一般把CEF4Delphi放在固定的第三方库目录里所有项目引用同一份这样升级维护最省事。另外提醒一下搜索路径里加的是source\cef3不是仓库根目录。加错层级的话编译时会找不到uCEFInterfaces.pas、uCEFApplication.pas这些核心单元错误一大片让人摸不着头脑。3.2 安装设计时包让 TChromium 出现在组件面板如果你偏好可视化拖拽就安装设计时包。去packages目录找跟Delphi版本匹配的工程文件比如CEF4Delphi_12.dproj之类先编译“Runtime”版本再编译“DesignTime”版本并右键Install。安装成功后在组件面板会多出一个CEF4Delphi或CEF4DelphiCommon的页签里面有TChromium、TChromiumWindow、TCefCustomScheme、TCEFApplication等几个主要组件。这里我要说一个经验安装设计时包之前确认你已经把CEF二进制文件放到了对应的输出目录或者确保能在系统PATH中找到。因为设计时包里有一部分组件在IDE设计器里可能就要初始化CEF环境的如果你DLL不对轻则控件拖不上窗体重则IDE直接崩溃非常烦人。以前我在某个开发机上装了个版本不匹配的CEF4Delphi设计时包导致IDE一打开包含TChromium的窗体就报“Access violation”最后只能CtrlShiftF11打开工程源文件把窗体资源里的组件引用手动删掉才恢复。这个坑我记忆犹新。如果你只想让程序正常工作不太在乎IDE里能不能看到可视化组件那我强烈建议跳过安装设计时包这一环直接用代码创建。运行时的代码和设计时包无关少一层组件安装就少一个冲突源头尤其在团队多人协作时每个人IDE环境里装的控件版本如果不一样很容易出现“我机器上好好的你机器上就打不开”的怪问题。3.3 从 FormCreate 到页面加载最小可用代码不管你用不用设计时包最终都要建立CEF的Application对象。在CEF4Delphi里通常在Program启动代码中先创建全局的GlobalCEFApp对象然后设置参数再启动消息循环。一个标准的最小工程dpr里大概是这样program MiniBrowser; uses VCL.Forms, uCEFApplication, MainForm in MainForm.pas {Form1}; {$R *.res} var GlobalCEFApp: TCefApplication; begin GlobalCEFApp : TCefApplication.Create; try // 一定要先初始化再创建窗体 if not GlobalCEFApp.StartMainProcess then Halt(1); Application.Initialize; Application.MainFormOnTaskbar : True; Application.CreateForm(TForm1, Form1); Application.Run; finally GlobalCEFApp.Free; end; end.这里最关键的代码是GlobalCEFApp.StartMainProcess它负责检查CEF初始化状态。如果CEF初始化失败说明DLL缺了或者资源文件路径不对程序会在这里直接退出不会让你看到窗体再闪退。窗体的OnCreate里如果是动态创建TChromium可以这么写procedure TForm1.FormCreate(Sender: TObject); begin FChromium : TChromium.Create(Self); FChromium.Parent : Self; FChromium.Align : alClient; // 直接设定要打开的地址 FChromium.DefaultURL : https://www.example.com; FChromium.CreateBrowser(Handle, ); end;CreateBrowser的第二个参数是额外的命令行参数一般传空字符串就行。如果你需要在加载前注入一些自定义脚本可以在这里传--disable-web-security之类的Chromium参数不过生产环境不建议乱开。运行起来以后你会看到任务管理器里出现你的程序名好几个同名进程这是正常的。首次使用CEF4Delphi的人经常被吓一跳以为程序开了多个实例其实这是Chromium的渲染进程、GPU进程等子进程的机制。4. CEF4Delphi 页面与 Delphi 代码双向通信从执行 JS 到 CefQuery4.1 在 Delphi 里给网页执行 JavaScript实际项目里八成以上功能需要Delphi去控制网页里面的行为。比如点一下Delphi窗体上的按钮网页里的某个表格要刷新、某个文本框要填充值、或者触发页面隐藏的导出逻辑。最简单的办法就是调用ExecuteJavaScript。假设页面上有一个id为txtSearch的输入框和一个id为btnSearch的按钮你在Delphi里可以这样模拟用户操作var script: string; begin script : document.getElementById(txtSearch).value客户A; document.getElementById(btnSearch).click();; FChromium.Browser.MainFrame.ExecuteJavaScript(script, , 0); end;ExecuteJavaScript方法的三个参数分别是JS代码、资源URL、行号。后面两个在正常情况下可以随便传但如果你需要在上线后根据JavaScript堆栈去定位页面报错最好把第二个参数写成页面URL或某个便于识别的标签。这样哪怕执行出错控制台日志里也能看到具体来源。需要注意的是FChromium.Browser可能为空比如浏览器还没创建完成时。在OnCreate里创建了TChromium后Browser属性并不会立即有效必须等底层的CEF浏览器对象初始化完成。所以我的习惯是先用一个布尔型标志位记录是否已初始化在事件回调OnAfterCreated里把标志置为True后续所有需要调用ExecuteJavaScript的操作都先判断这个标志。另外网页自身如果用了CSPContent Security Policy的script-src限制你用ExecuteJavaScript注入的脚本可能被浏览器拦截。这时候就要退回到requestContext的扩展注册或者在前端页面上做好预留接口而不是硬往里写大段脚本。我遇到过一个页面因为安全策略特别严格任何外联JS都禁掉了最后是让前端同事在页面里留了一个window.bridge对象Delphi这边只负责调用这个对象预设好的方法才算解决了问题。4.2 让网页调回 Delphi 方法网页主动调Delphi方法的需求也很常见比如网页里的按钮点击后要调用本地读卡器接口或者要把页面某个计算好的JSON结果回传给Delphi保存。CEF4Delphi里常用的思路是通过自定义Scheme协议或者通过TCefQuery机制但我觉得对大多数业务系统来说最直观的是在OnBeforeBrowse事件里拦URL或者在OnLoadEnd之后给网页注入一个桥接函数。这里给一个可靠且常用的做法在Delphi的浏览器组件上绑定OnBeforeBrowse事件。当网页尝试跳转到某个自定义协议地址比如myapp://action?paramxxx时Delphi拦截下来做处理然后直接把URL改成about:blank或阻止跳转。网页通过location.hrefmyapp://readcard?id1来触发。代码大概是procedure TForm1.FChromiumBeforeBrowse(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const request: ICefRequest; const isRedirect: Boolean; out Result: Boolean); var url: string; begin url : request.URL; if AnsiStartsText(myapp://, url) then begin HandleMyAppAction(Copy(url, 9, MaxInt)); Result : True; // 阻止真正跳转 end else Result : False; end;这种方案的好处是网页端实现成本极低前端甚至不需要引入额外的SDK。坏处是URL长度有上限不适合传特别多的数据。如果要传大段JSON可以把数据编码放到POST请求里然后在OnBeforeResourceLoad事件里拦截但那样代码复杂度瞬间上去了。我的原则是小消息走URL协议大消息走ExecuteJavaScript回填全局变量再触发事件两头配合最实用。4.3 事件驱动模型OnTitleChange、OnBeforeBrowse、OnLoadingStateChangeCEF4Delphi的事件模型是基于CEF的接口回调实现的TChromium暴露了很多VCL风格的事件常用的有这么几个OnTitleChange网页标题变化时触发可以用来更新主窗体的Caption。OnBeforeBrowse页面请求导航前触发用于拦截跳转优先级很高。OnLoadingStateChange页面加载状态改变比如开始加载、加载完成适合在这里控制进度条。OnLoadEnd某个frame加载完毕时触发。往页面注入JS桥接代码我一般放在这里做确保DOM已经存在。OnAddressChange地址栏变化适合实现自定义地址栏同步。OnConsoleMessage网页控制台日志会输出到Delphi调试页面时非常救命。Demos里给了我一个很好的习惯在OnLoadEnd里给页面注入一个全局对象。比如procedure TForm1.FChromiumLoadEnd(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; httpStatusCode: Integer); var script: string; begin if not(frame.IsMain) then Exit; script : window.delphiBridge { SayHello: function(name) { return Hello name; } };; frame.ExecuteJavaScript(script, , 0); end;这样网页里只要调用window.delphiBridge.SayHello(张三)就能得到返回值。而真正要返回给Delphi的数据还是靠拦截URL或使用扩展绑定到达桥接函数本身更多的只是给前端提供一个统一入口。整体来看这个模式足够应对绝大多数企业应用了。5. 像“控件版本冲突导致 IDE 丢失控件”这类问题的完整排查链路5.1 Delphi 里的控件“丢失”真相网上搜“Delphi 控件版本问题导致每次进入IDE都丢失控件”能看到一堆人辛辛苦苦把控件放到窗体上保存工程重新打开IDE控件却不见了要么提示“Class TChromium not found”要么组件在窗体上显示成空白框。真相多半是表单上的类名在IDE环境里没注册。不一定是你没装设计时包而是你装的包版本和工程里引用的版本不一致。CEF4Delphi也不例外。你在一台机器上用老版本编译出来的.DCU、.BPL换一台机器打开工程时IDE找到的却是新版本的包类名一样、属性列表变了就会在反序列化窗体资源时失败。轻则控件消失重则IDE报错拒绝打开窗体。我的标准动作是三步在IDE里显式执行一次“Component Install Packages”确认CEF4Delphi设计时包确实已安装而且只有一份。清空项目下的__history、*.dcu这些编译残留强制全量重编。在.dproj里检查搜索路径确保里面只有你当前要用的那一个source\cef3路径不要出现两个不同目录同时存在的情况。如果你并不需要可视化组件直接把TChromium相关代码全部放到一个单独的Unit里不放在.dfm上这样IDE打开窗体时根本不会去解析TChromium类就不会出现“控件丢失”的问题了。这也是我前面坚持动态创建组件的核心原因之一。5.2 白屏、DLL 缺失、进程异常结束的排查顺序CEF4Delphi运行期最常见的表现是程序能启动但浏览器区域完全白屏或者程序一闪而过。出现这类问题我的排查顺序已经固化了从成本低到成本高排确认DLL和资源文件都在exe同目录。重点看libcef.dll、icudtl.dat、snapshot_blob.bin、resources目录和locales目录是否齐全。缺一个icudtl.dat就够你白屏半天的。确认位数匹配。Win32工程放64位DLL或反过来都会导致初始化失败。确认命令行列了正确的--no-sandbox等参数。在部分Windows服务器环境、或者权限受限的域环境里CEF的沙箱进程可能起不来表现为程序一直卡在初始化。在GlobalCEFApp对象里设置一下相关参数能解决。确认路径有没有乱码或非英文字符。CEF对某些特殊字符路径处理得很奇怪如果程序放在带%、#、很长的中文路径下可能初始化失败。生产环境我一般会统一放到C:\Program Files\公司名\产品名这种目录避免各种妖蛾子。看Windows事件查看器里的应用程序日志。如果程序闪退日志里能找到崩溃模块的名字十有八九直接锁定是libcef.dll还是别的模块出了问题。按这个顺序排查90%的问题能在前两步解决。剩下的10%里有相当一部分是显卡驱动或者GPU加速导致的可以通过在GlobalCEFApp里关闭GPU硬件加速来处理做法就是把MultiThreadedMessageLoop等参数调整一下或者设置DisableGPUAcceleration : True。对大多数桌面业务系统来说关闭GPU加速不会造成肉眼可见的体验差异但换来了极高的稳定性。5.3 为什么 ActiveX 控件迁移到 Chromium 内核时要重写回到开头那个场景NTKO大文件上传、CA安全控件、LODOP打印控件这些老ActiveX控件在IE里能用在CEF4Delphi里能不能用我的答案是不能直接兼容。CEF4Delphi用的是Chromium内核Chromium本身不运行ActiveX也不支持IE的object标签激活ActiveX控件。你如果只是把TWebBrowser换成TChromium页面里还是object classidclsid:...那这一块在Chromium里就是完全空白甚至可能触发下载提示或显示“插件不受支持”。但这不意味着迁移无路可走只是要换个思路。对真正的业务系统来说老ActiveX控件扮演的角色往往就四类上传大文件。建议改成现代的上传组件比如用input typefile配合XMLHttpRequest或fetch分片上传服务端接收逻辑不变。调阅CA证书、UKey、身份证读卡器。这类硬件接口现在很多厂商都推出了Chrome/Edge支持的新版WebSDK或者提供本地服务加网页JS调用的方案旧控件可以直接退役。打印。LODOP新版本对Chrome内核也有支持可以通过WebSocket本地服务的方式调用不必再依赖ActiveX。签章、加密。和CA类似尽量推厂商的现代版SDK。我的经验是迁移前先梳理页面里每个ActiveX对象到底在干什么再决定对应方案。别一上来就硬改否则页面DOM结构动得太大前端同事要疯。我做过一个报表系统迁移原先页面里嵌了一个Excel风格的Formula One控件原本以为要重写表格所有交互逻辑后来发现那个控件其实就是读取服务端生成的XML展示成网格前端拿现成的开源表格库替换接口稍微改一下两周就搞定了。所以CEF4Delphi给你的是内核级升级的机会而不是单纯换个壳业务逻辑该重想的地方还是得重想。6. 生产环境里的实战细节缓存、多进程、输入法和发布目录6.1 CachePath 到底该不该设置CEF4Delphi默认情况下浏览器缓存是临时的程序关掉就丢。有些场景需要保存登录状态比如已经登录了某个后台系统不希望用户每次打开软件都重新输一遍用户名密码。这时候就必须给浏览器设置持久化缓存目录。在TChromium的OnBeforeCreated或GlobalCEFApp里设置CachePath。对于TChromium组件可以直接设置CachePath属性指向一个可写的目录比如GlobalCEFApp.CachePath : C:\AppData\MyApp\cef_cache;注意如果CachePath对应的目录没有写权限比如放在Program Files下面浏览器初始化会失败或者静默走到内存缓存模式表现为“登录状态保存不住”。生产环境我一般把缓存目录放在%LOCALAPPDATA%\MyApp\cef_cache下面既保证可写又不跟用户文档混在一起。缓存目录里会积累大量小文件时间长了体积变大可以考虑定期清理但千万别在程序运行时手动去删否则可能造成页面加载异常。6.2 多进程架构会吓到你的地方我之前说过CEF4Delphi跑起来之后任务管理器里会看到好几个你的程序名的进程。这是Chromium的架构不是程序开了多个实例。如果你是维护过这类程序的老人肯定见过用户打电话说“你们的软件为什么开了好几个占用内存那么大”。这里解释一下主进程是你的程序的常规进程负责UI、窗口、业务逻辑渲染进程负责跑网页的HTML/CSS/JSGPU进程负责加速渲染还有网络进程、存储进程等等视版本不同可能还有几个辅助进程。这些子进程在CEF里的生命周期由主进程管理正常情况下你不需要干预关闭主窗口后它们会自动退出。但如果你在程序里写了比较激进的“关闭进程”逻辑比如通过TerminateProcess强杀带有你EXE名的进程那就危险了。搞不好网页操作到一半渲染进程被误杀整个浏览器区域白屏。我的建议是开发期通过任务管理器熟悉一下这些进程上线后不要写任何依赖“唯一进程”的代码也给运维同事解释清楚这是正常现象。进程数变多内存占用确实比纯UI程序高但换来的是隔离和稳定对于企业级应用来说这个代价是值得的。6.3 中文输入法问题在CEF4Delphi嵌入的网页里输入中文有些朋友会遇到输入法弹不出来或者输入法光标位置不对候选框跑到屏幕角落去的情况。这个问题基本和Windows下的IME输入法管理器和Chromium子窗口焦点管理有关。我的经验是首先要确保你的TChromium控件在获得焦点时CEF的窗口句柄也收到了焦点。可以在OnGotFocus事件里调用FChromium.SetFocus(True)或者使用TCefWindowParent等封装组件来承载浏览器。如果你是自己动态创建的TChromium建议设置FChromium.TabStop : True保证Tab切换焦点时不会跳过浏览器区域。某些三方输入法像搜狗、QQ输入法在CEF里偶尔出现候选框不跟随这是Chromium内核的已知问题不是CEF4Delphi特有。临时解决方案通常是升级到最新版Chromium对应版本或者设置EnableIME相关属性。如果你系统对输入体验要求极高建议在演示阶段就多测几款输入法尤其是你们客户机房常用那几款。另外有些工控软件会用到虚拟键盘这类特殊输入法在CEF4Delphi和虚拟键盘的窗口协作上偶尔也需要手动调整窗口弹起的位置。这种问题属于边缘场景真遇到了再查具体输入法厂商的技术支持吧不是很普遍但确实会存在。6.4 发布目录的正确文件列表写到了发布阶段我把最终发布时建议包含的文件整理成一个清单方便你对照。程序所在目录至少要有这些你的主程序.exelibcef.dlllibEGL.dlllibGLESv2.dllicudtl.datsnapshot_blob.bin、v8_context_snapshot.binv8_context_snapshot.bin一般也叫v8_context_snapshot.bin或v8_context_snapshot_64.bin具体看CEF版本resources子目录包含各种.pak文件比如chrome_100_percent.pak、chrome_200_percent.pak、resources.paklocales子目录不需要全量语言包可以根据你的客户地域只留zh-CN.pak、en-US.pak体积能省不少如果你用了自定义协议或扩展还会有对应文件正常情况下列这些就够了还记得我说过CEF四类DLL很可能触发杀毒软件误报吗尤其libcef.dll会被某些安全软件当毒扫。这个问题在交付给客户时经常遇到处理办法就是在公司层面给杀毒软件厂商提交误报申诉或者给客户IT一个文件校验和让他们在杀毒系统里加白名单。提前做别等客户现场炸了再救火。DLL版本对齐也很重要。你开发时用CEF 116版本交付时升级到CEF 128版本往往表面上看不出差别但某些API行为会变。我吃过一次亏旧版CEF里ExecuteJavaScript同步执行没问题新版里对某些复杂表达式会丢返回值排查了一天才发现是升级后CEF版本把JavaScript执行变成了异步任务。所以项目进行到中后期尽量锁死版本不要频繁升级CEF二进制包。写到这里实际上你已经把CEF4Delphi从下载、编译、集成、交互到发布的整条链路都过了一遍。我最后再分享一点个人习惯每换一个CEF版本我都会先跑一遍官方demos里的几个示例再跑自己的核心业务页面通过对比demo是否正常来快速定位是环境问题、还是业务代码兼容问题。这个习惯帮我省了很多“开发环境和客户环境差一点”的冤枉时间。Delphi 12.3搭配CEF4Delphi说白了就是把Web这层能力彻底从古董壳子里面解放出来剩下的就是你业务逻辑上把它用得有多顺手了。本文还有配套的精品资源点击获取
返回列表