You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:39:25