Net-Base Iris

14.06.2026

Delphi WebView2 i FMX: tosú go glan, JS-Bridge a thógáil, íosluchtuithe agus dífhabhtú faoi smacht

Tá WebView2 i FireMonkey cosúil le 'brabhsálaí a ionchur go simplí', ach sa chleachtas teipeann sé le linn an tús, le himeachtaí nascleanaithe, leis an droichead JS↔Delphi, le láimhseáil íoslódála agus le dífhabhtú. Taispeánann an sleamhnán cód seo patrún láidir le freagrachtaí soiléire...

14.06.2026

Ó théama an iris go cleachtas tionscadail

Leathanaigh seirbhíse agus teicniúla oiriúnacha don alt

Má tá duine i mbogearra gnó atá ann cheana ag iarraidh ábhar gréasáin nua‑aimseartha a ionchlannú “go tapa”, téann sé chuig Windows le WebView2. I Delphi WebView2 FMX is annamh atá an fhadhb lárnach ag taispeáint URL; is é an dúshlán ná ionchlannú glan i gcomhéadan FireMonkey (FMX), an túsú iontaofa (asíncrónach agus bunaithe ar COM), agus na greimtheidí Edge maidir le fillteáin sonraí úsáideora, íoslódálacha, dífhabhtú agus cumarsáid JS↔Delphi atá seasmhach.

An sliocht foinsí seo léiríonn patrún a mholaim do fheidhmchláir inmharthana: réad «Host» scagtha a rialálann an WebView2‑lifecycle, agus droichead sonraithe trí WebMessage (JSON), in ionad «ExecuteScript áit ar bith» gan smacht. Níl sé mar aidhm demo‑chód a sholáthar, ach codán a fhéadfadh maireachtáil i gcliaint atá fhorbartha le himeacht ama.

Cén fáth go bhfuil WebView2 i FMX difriúil ó „Browser-Component drop“

Is API í WebView2 atá an‑ghar do COM/WinRT agus a éilíonn túsú asíncrónach. Cé go ndéantar FireMonkey ailtireacht ar láimhseálacha Windows, beidh de dhíth ort ag an deireadh fíor-Parent-Window (HWND) agus sreangú rialaithe d’athmhéid/fócas. Ag an am céanna, ní reáchtáiltear imeachtaí i gcónaí sa áit a mbeifeá ag súil leo in FMX. Má thosaíonn tú anseo go “quick and dirty”, faigheann tú de ghnáth:

  • AVanna tréimhsiúla agus an fhoirm á dhúnadh (tagann callbácsanna i ndiaidh Destroy)
  • imeachtaí nascleanúna ó chomhthéacs snáithe mícheart
  • fadhbanna buanaithe/taisce nach bhfuil iontaofa mar gheall ar straitéis neamhshoiléir don fhillteán sonraí úsáideora
  • ní bhíonn íoslódálacha nó dialóga íoslódála a bhíonn “ag greamú”
  • dífhabhtú a fhaightear ar bhonn na n‑ádh seachas trí chumraíocht shoiléir do Remote‑Debugging

Is é an antidot an lifecycle soiléir: Create → InitializeAsync → Attach → Navigate → Detach/Dispose – agus teorannú shoiléir idir an UI agus innill an bhrabhsálaí.

Sliocht foinsí: WebView2Host für Delphi WebView2 FMX

An cód thíos sketchálann rang Host scagtha a dhéanann (1) cumraíocht an WebView2 Environment, (2) an Controller‑objekt a nascleanúint le HWND, (3) imeachtaí nascleanúna agus íoslódála a shreangú agus (4) droichead JS bunaithe ar JSON a sholáthar tríd an WebMessageReceived. Tá an cód deartha le hintinn ailtireachta: cuimsíonn sé tagairtí COM, seachnaíonn sé callbácsanna a thagann i ndiaidh Destroy, agus ceadaíonn sé teorainneacha oibriúcháin cosúil le ‚in aghaidh úsáideora‘ nó ‚in aghaidh meaisín‘ le fillteáin sonraí úsáideora ar leith.

unit WebView2Host;

interface

uses
System.SysUtils, System.Classes, System.IOUtils, System.JSON,
Winapi.Windows, Winapi.ActiveX,
FMX.Types,
WebView2, WebView2_TLB; // ag brath ar an tsocraíocht: WebView2.pas nó Import-TLB

type
TWebView2JsonMessage = record
Name: string;
CorrelationId: string;
Payload: TJSONObject;
class function TryParse(const Json: string; out Msg: TWebView2JsonMessage): Boolean; static;
end;

TOnWebMessage = reference to procedure(const Msg: TWebView2JsonMessage);
TOnDownload = reference to procedure(const FileName, MimeType: string; TotalBytes: Int64);

TWebView2Host = class
private
FParentHwnd: HWND;
FUserDataFolder: string;
FEnvironment: ICoreWebView2Environment;
FController: ICoreWebView2Controller;
FWebView: ICoreWebView2;
FDestroyed: Boolean;
FOnWebMessage: TOnWebMessage;
FOnDownload: TOnDownload;

procedure EnsureNotDestroyed;
function MakeUserDataFolder: string;

// Event handler
procedure HookEvents;
procedure UnhookEvents;

procedure OnWebMessageReceived(
const sender: ICoreWebView2;
const args: ICoreWebView2WebMessageReceivedEventArgs);

procedure OnDownloadStarting(
const sender: ICoreWebView2;
const args: ICoreWebView2DownloadStartingEventArgs);

public
constructor Create(AParentHwnd: HWND; const AUserDataFolder: string = “);
destructor Destroy; override;

procedure InitializeAsync;
procedure Navigate(const Url: string);
procedure Resize(const Bounds: TRect);

procedure PostJsonToWeb(const Obj: TJSONObject);
procedure SetDevToolsEnabled(const Enabled: Boolean);

property WebView: ICoreWebView2 read FWebView;
property OnWebMessage: TOnWebMessage read FOnWebMessage write FOnWebMessage;
property OnDownload: TOnDownload read FOnDownload write FOnDownload;
end;

implementation

{ TWebView2JsonMessage }

class function TWebView2JsonMessage.TryParse(const Json: string; out Msg: TWebView2JsonMessage): Boolean;
var
V: TJSONValue;
O: TJSONObject;
begin
Result := False;
Msg.Name := “;
Msg.CorrelationId := “;
Msg.Payload := nil;

V := TJSONObject.ParseJSONValue(Json);
try
if not (V is TJSONObject) then Exit;
O := TJSONObject(V);

Msg.Name := O.GetValue(’name‘, “);
Msg.CorrelationId := O.GetValue(‚cid‘, “);

// D’fhéadfadh an payload a bheith in easnamh nó null
if O.TryGetValue(‚payload‘, Msg.Payload) then
Msg.Payload := TJSONObject(Msg.Payload.Clone)
else
Msg.Payload := TJSONObject.Create;

Result := Msg.Name <> “;
finally
V.Free;
end;
end;

{ TWebView2Host }

constructor TWebView2Host.Create(AParentHwnd: HWND; const AUserDataFolder: string);
begin
inherited Create;
FParentHwnd := AParentHwnd;
FUserDataFolder := AUserDataFolder;
FDestroyed := False;
end;

destructor TWebView2Host.Destroy;
begin
FDestroyed := True;

// Scolaítear na himeachtaí sula scaoiltear na réada COM.
UnhookEvents;

FWebView := nil;
FController := nil;
FEnvironment := nil;

inherited;
end;

procedure TWebView2Host.EnsureNotDestroyed;
begin
if FDestroyed then
raise EInvalidOperation.Create(‚Tá WebView2Host scriosta cheana féin.‘);
end;

function TWebView2Host.MakeUserDataFolder: string;
begin
if FUserDataFolder <> “ then
Exit(FUserDataFolder);

// Sa chleachtas: de réir app agus de réir úsáideora Windows, ní sa fillteán cláir
Result := TPath.Combine(TPath.GetHomePath, ‚AppDataLocalMyCompanyMyAppWebView2‘);
ForceDirectories(Result);
end;

procedure TWebView2Host.InitializeAsync;
var
UserData: string;
Opt: ICoreWebView2EnvironmentOptions;
begin
EnsureNotDestroyed;

UserData := MakeUserDataFolder;

// Roghanna: anseo is féidir argóintí breise brabhsálaí a chur isteach, m.sh. Remote-Debug
Opt := TCoreWebView2EnvironmentOptions.Create;

// Async CreateEnvironment
OleCheck(CreateCoreWebView2EnvironmentWithOptions(
nil, PWideChar(UserData), Opt,
TCoreWebView2CreateCoreWebView2EnvironmentCompletedHandler.Create(
procedure (errorCode: HRESULT; const createdEnvironment: ICoreWebView2Environment)
begin
if FDestroyed then Exit;
OleCheck(errorCode);

FEnvironment := createdEnvironment;

// Controller an Parent HWND binden
OleCheck(FEnvironment.CreateCoreWebView2Controller(
FParentHwnd,
TCoreWebView2CreateCoreWebView2ControllerCompletedHandler.Create(
procedure (errorCode2: HRESULT; const createdController: ICoreWebView2Controller)
begin
if FDestroyed then Exit;
OleCheck(errorCode2);

FController := createdController;
OleCheck(FController.get_CoreWebView2(FWebView));

HookEvents;

// Initial sichtbar machen
FController.put_IsVisible(1);
end)));
end)));
end;

procedure TWebView2Host.HookEvents;
var
TokenMsg, TokenDl: EventRegistrationToken;
begin
if (FWebView = nil) then Exit;

// WebMessageReceived (JS->Delphi)
TokenMsg.value := 0;
OleCheck(FWebView.add_WebMessageReceived(
TCoreWebView2WebMessageReceivedEventHandler.Create(
procedure(const sender: ICoreWebView2; const args: ICoreWebView2WebMessageReceivedEventArgs)
begin
if FDestroyed then Exit;
OnWebMessageReceived(sender, args);
end), TokenMsg));

// DownloadStarting
TokenDl.value := 0;
OleCheck(FWebView.add_DownloadStarting(
TCoreWebView2DownloadStartingEventHandler.Create(
procedure(const sender: ICoreWebView2; const args: ICoreWebView2DownloadStartingEventArgs)
begin
if FDestroyed then Exit;
OnDownloadStarting(sender, args);
end), TokenDl));

// Nóta: chun an unhooking a dhéanamh buan, ba chóir duit na token a stóráil.
// I go leor tionscadal bíonn sé seo sách má mhaireann an host chomh fada leis an fhoirm.
end;

procedure TWebView2Host.UnhookEvents;
begin
// Leagan chobhsaí: na token a choinneáil agus remove_* a ghlaoch.
// Mar thrácht amháin: mar gheall ar éagsúlacht shocruithe an import-unit agus an bhainistíochta token de réir an wrapper.
end;

procedure TWebView2Host.OnWebMessageReceived(
const sender: ICoreWebView2;
const args: ICoreWebView2WebMessageReceivedEventArgs);
var
Json: PWideChar;
S: string;
Msg: TWebView2JsonMessage;
begin
Json := nil;
OleCheck(args.TryGetWebMessageAsString(Json));
try
S := Json;
finally
CoTaskMemFree(Json);
end;

if Assigned(FOnWebMessage) and TWebView2JsonMessage.TryParse(S, Msg) then
begin
try
FOnWebMessage(Msg);
finally
Msg.Payload.Free;
end;
end;
end;

procedure TWebView2Host.OnDownloadStarting(
const sender: ICoreWebView2;
const args: ICoreWebView2DownloadStartingEventArgs);
var
Dl: ICoreWebView2DownloadOperation;
Uri, Mime, ResultFile: PWideChar;
Total: Int64;
FileName: string;
begin
Uri := nil;
Mime := nil;
ResultFile := nil;

OleCheck(args.get_DownloadOperation(Dl));
OleCheck(Dl.get_TotalBytesToReceive(Total));

// Sa chleachtas: is minic a bhíonn ResultFileName ar dtús folamh, ag brath ar an bhfoinse.
OleCheck(Dl.get_ResultFilePath(ResultFile));
OleCheck(Dl.get_MimeType(Mime));
OleCheck(Dl.get_Uri(Uri));

try
FileName := ExtractFileName(string(ResultFile));
if FileName = “ then
FileName := ‚download.bin‘;

if Assigned(FOnDownload) then
FOnDownload(FileName, string(Mime), Total);

// Roghnach: UI íoslódála féin, ansin socraigh Handled
// args.put_Handled(1);
finally
CoTaskMemFree(Uri);
CoTaskMemFree(Mime);
CoTaskMemFree(ResultFile);
end;
end;

procedure TWebView2Host.Navigate(const Url: string);
begin
EnsureNotDestroyed;
if FWebView = nil then
raise EInvalidOperation.Create(‚Níl WebView2 fós initalaithe.‘);

OleCheck(FWebView.Navigate(PWideChar(Url)));
end;

procedure TWebView2Host.Resize(const Bounds: TRect);
var
R: tagRECT;
begin
if FController = nil then Exit;
R.Left := Bounds.Left;
R.Top := Bounds.Top;
R.Right := Bounds.Right;
R.Bottom := Bounds.Bottom;
OleCheck(FController.put_Bounds(R));
end;

procedure TWebView2Host.PostJsonToWeb(const Obj: TJSONObject);
var
S: string;
begin
EnsureNotDestroyed;
if FWebView = nil then Exit;

S := Obj.ToJSON;
OleCheck(FWebView.PostWebMessageAsString(PWideChar(S)));
end;

procedure TWebView2Host.SetDevToolsEnabled(const Enabled: Boolean);
var
Settings: ICoreWebView2Settings;
begin
if (FWebView = nil) then Exit;
OleCheck(FWebView.get_Settings(Settings));
OleCheck(Settings.put_AreDevToolsEnabled(Ord(Enabled)));
end;

end.

Cuspóir an chur chuige

  • Capsúlú an saolré: Ní aithníonn an Fhoirm FMX ach “Initialize/Navigate/Resize”, ní sonraí COM.
  • Droichead le conradh: Tá teachtaireachtaí JSON le name, go roghnach cid (Correlation-ID) agus payload indéanta le cothabháil agus iniúchadh.
  • Persistíocht chobhsaí don oibriú: cosc ar UserDataFolder rialaithe ar chros-choincidí caché, fadhbanna ceadanna agus an fhadhb “oibríonn sé ar ríomhairí forbróra, ní i dtimpeallacht táirgthe”.

JS↔Delphi-Bridge: cén fáth go bhfuil WebMessage níos cobhsaí ná ExecuteScript

Tugann WebView2 roinnt bealaí chun cumarsáide a dhéanamh. Sa chleachtas bíonn ExecuteScript tarraingteach, ach deacair a leaganú: cuireann tú sreingeanna isteach i n-interpretóir gan cainéil freagartha soiléire agus gan léiriú earráidí atá iontaofa. Is canal sainmhínithe é PostWebMessageAsString / WebMessageReceived i gcomparáid.

Cás imeartha a théann i bhfeidhm go minic i dtimpeallachtaí corparáideacha: ní mór duit ó Web-Frontend (m.sh. calafort inmheánach) sreabhadh oibre Delphi a thosú (priontáil, rochtain ar ghléasanna, comhtháthú legacy). Ansin teastaíonn uait:

  • liosta bán de ainmneacha teachtaireachta
  • Correlation-IDs do fhreagraí asíncrónacha
  • áit lárnach a fhíordheimhníonn payloads (m.sh. réimsí riachtanacha, teorainneacha méide)

Sna hóstach is í an áit sin an OnWebMessageReceived. Ba cheart an fíordheimhniú féin a chur i sraith os cionn (m.sh. Application-Service), ionas go mbíonn teicneolaíocht UI/WebView2 agus loighic ghnó scartha (ailtireacht sraithe clasaiceach: UI → Application → Domain → Infrastruktur) .

Íosluchtuithe agus stóráil comhad: rudaí a chuireann iontas i gcórais oibríochta

Rithtear íosluchtuithe i WebView2 trí ICoreWebView2DownloadOperation. Ag brath ar an bhfoinse d’fhéadfadh ResultFilePath a bheith folamh go luath nó a chur ar bun níos déanaí. Ina theannta sin, ní mhaith le go leor cuideachtaí go sábhálfadh úsáideoirí deiridh i bhfeidhm fillteáin neamh-rialaithe.

Cleachtais moltaí:

  • Gabháil DownloadStarting agus trí args.put_Handled(1) an UI a láimhseáil tú féin (cosán tiomnaithe, comhdhéanamh ainm, fillteán coraintíne).
  • Teorainneacha méide comhaid agus seiceálacha cineál-MIME chun “logfhaisnéis 4 GB de thaisme” a sheachaint.
  • Auditáil: scríobh méata-shonraí íoslódála (URI, MIME, bytes) isteach i do lógbhailte, ní an t-ábhar féin.

Má tá próisis rialaithe agat (m.sh. ceaduithe, infheictheacht), is iad na himeachtaí seo an t-aon áit ina bhféadfaidh tú ‘domhan na mbrabhsálaithe’ a cheangal le do rialacha oibríochta.

Dífhabhtú: DevTools, Remote Debug Port agus staidí in-athghinte

Is minic a theipeann ar dhífhabhtú WebView2 toisc nach féidir staidí a athchruthú go iontaofa. Cabhraíonn dhá shreangrianta:

  • Cumasaigh/díchumasaigh DevTools trí ICoreWebView2Settings (sa chód: SetDevToolsEnabled) – sa Release go minic múchta, i gcás tacaíochta casadh orthu go sainiúil.
  • UserDataFolder cobhsaí: má theastaíonn ó do thacaíocht botún a athchruthú, is luachmhar cosán shonraithe é. Is féidir an fillteán a shábháil/zipáil (aire: cosaint sonraí/PII) agus staidí a chur i gcomparáid go dírithe.

Roghnach (ag brath ar an wrapper) is féidir leat EnvironmentOptions a sholáthar le argóintí breise brabhsálaí, m.sh. Port Remote-Debug. Tá sé seo úsáideach má theastaíonn uait aip a anailísiú ar thástáilshonraí gan uirlisí forbróra áitiúla. Teorainneacha: i dtimpeallachtaí táirgeachta caithfear é seo a cheadú agus a dhoiciméadú go soiléir, nó cruthaíonn tú dromchla ionsaithe breise nach bhfuil riachtanach.

Fadhbanna coitianta i Delphi WebView2 FMX: COM, snáithí agus saolré na foirme

1) Callbacks nach dem Schließen

Is féidir leis na CompletedHandler asínchrónacha teacht isteach tar éis don fhoirm a bheith ag dúnadh cheana féin. Sa shnippéad coinníonn FDestroyed rochtain ar réada a bhfuil scaoileadh orthu. Tá sé níos láidre freisin:

  • Coinnigh tóicíní d’imeachtaí agus glaoigh go glan remove_* i Destroy
  • Ceadaigh InitializeAsync uair amháin amháin (State-Machine: Created/Initializing/Ready/Disposed)

2) Thread-Kontext

Bíonn go leor láimhseálaithe “UI-nach” i ndáiríre, ach ná brath orthu go mbeidh tú in ann scríobh go díreach i rialuithe FMX. Má nuashonraíonn tú an UI in OnWebMessage, is í TThread.Queue(nil, ...) an rogha shábháilte. Roinnim seo go soiléir: bailíonn an host an t-imeacht, cinneann an Application-Service, agus déantar an UI a nuashonrú eisiach trí Queue.

3) DPI/Resize und FMX-Layouts

Ríomhann FMX in aonaid loighiciúla, agus tá WebView2 ag súil le Pixel-Rects. Sa chleachtas, tá áit shoiléir de dhíth ort ina aistríonn tú teorainneacha ó rialuithe FMX go picteilí iarbhír. Glacann an snippéad TRect; ina fhoirm ba chóir duit comhordanáidí WinAPI a ghiniúint as sin (m.sh. trí FMX.Platform.Win agus Handle-APIs). Má scálaíonn an aip de réir DPI monatóra, tástáil an t-aistriú idir monatóirí: tá WebView2 níos íogaire anseo ná rialuithe FMX ghlan.

Cathain a bhíonn WebView2 i FMX ina infheistíocht cheart — agus cathain nach bhfuil

Tá WebView2 tairbheach má tá tú ag iarraidh teicneolaíocht gréasáin a úsáid go spriocdhírithe i bhfeidhmchlár cliant Delphi atá fhorbartha: radhairc riarthóirí ionsuite, sreafaí logála isteach OAuth/OIDC, tuairiscí HTML, portail inmheánach nó micro-frontends rialaithe. Tá sé praiticiúil freisin mar dhroichead nuachóirithe, chomh fada agus a ghearrann tú na freagrachtaí go soiléir agus nach mbeidh an droichead ina dhoras ciúin neamh-rialaithe don loighic ghnó.

Teorainneacha an chur chuige:

  • Plattform: Tá an patrún lárnach do Windows. Tá FMX ilfhorbartha, ach ní bhíonn WebView2 amhlaidh. Do macOS/iOS/Android beidh ort WebViews eile nó sraith abatartha a úsáid.
  • Security/Hardening: Nuair a luchtófar ábhar seachtrach, caithfidh tú nascleanúint, domaines a cheadú agus spriocanna íoslódála a theorannú go docht. Ba chóir go mbeadh sé seo i riachtanais, ní ina “dhiaidh sin”.
  • Support: Ní mór UserDataFolder agus spleáchais ar an runtime (WebView2 Runtime) a bheith mar chuid den choincheap oibriúcháin/rollout.

Conclúid

Delphi WebView2 FMX níl sé mar gadget UI; is comhpháirt chomhtháthaithe é le saolré féin. Má chomhtháineann tú an t-uainiú tosaigh, an eventing, UserDataFolder agus an JS-Bridge i gcaidrimh struchtúrtha, beidh WebView2 ina bhloic thógála seasmhach do sholáthairtí corparáideacha digití: Web-UI áit a bhfuil sé loighciúil, agus loighic Delphi áit a bhfuil sí le bheith. Má ghníomhaíonn tú scripteanna go neamh-rialaithe, má fágann tú bealaí don tsuim, agus má fhágann tú imeachtaí gan iad a dhíchur, gheobhaidh tú an cineál earráidí “sporadach sa réimse” a ídíonn am agus a laghdaíonn muinín.

Mura bhfuil tú cinnte agus ba mhaith leat WebView2 a chomhtháthú go glan i bhfeidhmchlár Delphi atá ann cheana, nó má theastaíonn measúnú teicniúil ar imeall nuachóirithe, labhair linn:

Sa chomhthéacs ghairmiúil, tá ról tábhachtach ag Webview2 Firemonkey agus Delphi Fmx Edge Browser nuair is gá go n-oibríonn comhtháthuithe, sreafaí sonraí agus forbairt leanúnach le chéile go soiléir.

Pléigh tionscadal nó tionscnamh nuachóirithe le Net-Base.

Céim eile

Nuair a éiríonn an t-ábhar seo ina thionscadal fíor, ba chóir ailtireacht, an córas reatha agus an t-oibriú a mheas le chéile go luath.

Ní hamháin go dtacaímid le ceisteanna aonair, ach freisin nuair is gá ó shlisíní cód foinse, ó ábhair legacy nó ó smaointe portail tionscadal corparáideach iontaofa a fhorbairt.

  • Measúnítear an staid reatha, an stát sprioc agus na rioscaí teicniúla le chéile.
  • Ní chuirfear REST, rochtain ar shonraí, portalí agus Rollout siar mar iarmhairtí.
  • Feiceann sibh go luath cé acu an cosán atá inbhuanaithe ó thaobh eacnamaíochta agus oibríochta.

Roinn an post

Roinn an t-alt seo go díreach

Tá LinkedIn, X, XING, Facebook, WhatsApp agus ríomhphost ar fáil láithreach. Do Instagram ullmhaímid nasc agus téacs gairid láithreach.

Ríomhphost

Osclaítear Instagram i gcluaisín nua. Cóipeáiltear an nasc agus an téacs gairid roimh ré isteach sa ghearrthaisce.