如何在FireMonkey环境下实现JavaScript向Delphi传递数据?
Delphi CEF:JavaScript调用Delphi方法的实现方案
我在Delphi中使用CEF(Chromium Embedded Framework)已实现Delphi向JavaScript传递数据,但无法实现JavaScript调用Delphi方法。尝试以下JS代码均无效:
JS_DELPHI._geta();
TMyExtension._geta();
相关Delphi代码如下:
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, ceffmx, FMX.Edit , ceflib , uCEFBaseRefCounted, uCEFInterfaces, uCEFTypes, uCEFListValue, uCEFBrowser, uCEFFrame, uCEFRequest, uCEFv8Context, uCEFv8Exception, uCEFv8StackTrace, uCEFDomNode, uCEFProcessMessage, uCEFApplicationCore; type TForm1 = class(TForm) ChromiumFMX1: TChromiumFMX; Button1: TButton; Edit1: TEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; type //这里建议用class 不建议用class(TThread) 不然有些地方要报错 TMyExtension = class(TThread) // or just class, (extension code execute in thread) public class function _geta:string; end; TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn) protected procedure OnWebKitInitialized; override; end; var Form1: TForm1; d : Integer ; m : TMyExtension ; CefRenderProcessHandler : TCustomRenderProcessHandler ; implementation {$R *.fmx} {$R *.LgXhdpiPh.fmx ANDROID} {$R *.XLgXhdpiTb.fmx ANDROID} {$R *.SSW3.fmx ANDROID} procedure TForm1.Button1Click(Sender: TObject); begin ChromiumFMX1.Load('http://localhost/index.html'); Edit1.Text := '555 '; ShowMessage('hiiiiiiiiiiiiiiiii'); end; procedure TForm1.Button2Click(Sender: TObject); begin ChromiumFMX1.Browser.MainFrame.ExecuteJavaScript(' d1();',ChromiumFMX1.browser.MainFrame.GetURL, 0); end; class function TMyExtension._geta: string; begin ShowMessage('dddddddddddddddddddddddd'); Result:='salam'; end; procedure TCustomRenderProcessHandler.OnWebKitInitialized; begin {$IFDEF DELPHI14_UP} TCefRTTIExtension.Register('JS_DELPHI', TMyExtension); {$ENDIF} end; initialization CefRemoteDebuggingPort := 9000; CefRenderProcessHandler := TCustomRenderProcessHandler.Create; CefBrowserProcessHandler := TCefBrowserProcessHandlerOwn.Create; end. end.
问题修复方案
1. 修正扩展类继承关系
TMyExtension不需要继承TThread,直接继承TObject即可,线程类会导致CEF上下文注册失败:
TMyExtension = class(TObject) public class function _geta: string; end;
2. 移到正确的上下文注册时机
CEF的RTTI扩展需要在V8上下文创建时注册,而非OnWebKitInitialized,重写OnContextCreated方法:
TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn) protected procedure OnWebKitInitialized; override; procedure OnContextCreated(const browser: ICefBrowser; const frame: ICefFrame; const context: ICefv8Context); override; end; // 实现方法 procedure TCustomRenderProcessHandler.OnContextCreated(const browser: ICefBrowser; const frame: ICefFrame; const context: ICefv8Context); begin inherited; {$IFDEF DELPHI14_UP} TCefRTTIExtension.Register('JS_DELPHI', TMyExtension); {$ENDIF} end; procedure TCustomRenderProcessHandler.OnWebKitInitialized; begin inherited; // 原注册代码移至OnContextCreated end;
3. 处理线程同步问题
CEF渲染进程运行在非UI线程,直接调用ShowMessage会导致异常,需同步到主UI线程:
class function TMyExtension._geta: string; begin TThread.Synchronize(nil, procedure begin ShowMessage('dddddddddddddddddddddddd'); end); Result := 'salam'; end;
4. 正确的JavaScript调用方式
确保页面加载完成后调用方法,避免上下文未初始化:
window.addEventListener('load', function() { var res = JS_DELPHI._geta(); console.log('Delphi返回值:', res); });
5. 额外检查
- 确认Delphi版本为XE及以上(支持
DELPHI14_UP宏) - 确保CEF初始化时
CefRenderProcessHandler已正确赋值
内容的提问来源于stack exchange,提问作者melina
相关产品推荐
相关产品推荐

