Ó 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 roghnachcid(Correlation-ID) aguspayloadindéanta le cothabháil agus iniúchadh. - Persistíocht chobhsaí don oibriú: cosc ar
UserDataFolderrialaithe 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_*iDestroy - Ceadaigh
InitializeAsyncuair 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
UserDataFolderagus 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.
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.