RAD Studio 10.4.1's TEdgeBrowser and javascript interaction-Chromium-based Edge browser control usage 2

table of Contents

RAD Studio 10.4.1's TEdgeBrowser and javascript interaction-Chromium-based Edge browser control usage 2

       First, let's take a look at the effect of running the code

        1.1. Browse Bootstrap responsive H5 pages smoothly

        1.2. It only takes one sentence to capture page pictures in variable proportions

         1.3. The execution of javascript is one sentence

       Second, how to achieve Delphi code

        1.1. Write html page code and add the click event of the page element

        1.2, write delphi event code

       Three, paste all the Delphi source code to you

        1.1. For details on the interface, please refer to the previous article "RAD Studio 10.4.1 New Chromium-based Microsoft Edge Browser TEdgeBrowser Control Usage"

         1.2. The code is as follows:

 Attachment: Related blog posts of this blog:

 If you like it, just click like and favorite below, so that you can watch the next sharing:


 

RAD Studio 10.4.1's TEdgeBrowser and javascript interaction-Chromium-based Edge browser control usage 2

        Now that delphi has TEdgeBrowser on the server, it can easily communicate with javascript, thanks to the Chromium-based Microsoft Edge browser. Not only that, but also Delphi's desktop c/s multi-tier distributed application client, TEdgeBrowser also It allows the Edge browser to access the Bootstrap responsive H5 page very smoothly, and it will never change its shape.

       First, let's take a look at the effect of running the code

        1.1. Browse Bootstrap responsive H5 pages smoothly

        1.2. It only takes one sentence to capture page pictures in variable proportions

 

 

         1.3. The execution of javascript is one sentence

 

       Second, how to achieve Delphi code

        1.1. Write html page code and add the click event of the page element

            For example: <p> tag page element, its id="mytestclick", inline display as "test you click me", write a click event of οnclick="handleclick() for it, which is the part shown in the figure below, and the rest < webview> and its corresponding external js file reference "webview2.js" written by me can ignore it:

             code show as below:

<!doctype html>
<html lang="zh-CN">
 <head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible">
		<meta name="viewport" content="width=device-width, initial-scale=1">
  		<title>我是mytest.html的网页标题</title>
 </head>
 <body>
		<webview style="width:100%;height:100%;" id="webview" >	
				<p onclick="handleclick()" id="mytestclick">测试你点我</p>
				<script type="text/javascript">
					function handleclick() {
						try{
					      window.chrome.webview.postMessage(
						      { data: 'Message from Edge Chromium', url: window.document.url }
						  );
						}catch(error){
						  console.log("postMessage error: " + error);
						}					    
					    console.log("测试这个点击事件执行了");
					}
				</script>
		</webview>
		<script src="js_lib/webview2.js"  type="text/javascript"></script>
 </body>
</html>

 

        1.2, write delphi event code

            Write button [call js] click event: 

  •             have to be aware of is:

            1.2.1. TEdgeBrowser.ExecuteScript executes the js string in a slightly different way from Intraweb. You can’t add the <script></script> tag, otherwise it won’t be executed, you just need to put the js code in it Just add it, just like importing external .js files; 

            1.2.2. If the js function has a return value, if you need to associate it with the html interface element, please associate and assign the value in an inline manner, for example: document.getElementById("mytestclick").innerHTML = "I will change it ! Who told you to click (beat) me!"; 

            1.2.3, develop the habit of using threads. b/s client: "Browser" is the same as our c/s client App, otherwise the "browser" UI will also have a bad UE experience of "it seems a bit stuck". 

procedure TForm_EdgeBrowser01.BitBtn_HandlePostmessageClick(Sender: TObject);
var LJs:string;
begin
  LJs:=
    //'<script type="text/javascript">'//:千万不能加,加了就不执行了:跟外部js文件类似,可从外部导入
      //'return 12;'+//:一旦返回:就不弹出了:
       'window.alert("既然你让我弹出,那你一点’‘确定’‘我就:");'
       (*'webview.contentWindow.postMessage.postMessage('
			   +'{ data: "既然你让我弹出,那你一点’‘确定’‘我就:", , "*" }'
				 +');'//*)
      +'document.getElementById("mytestclick").innerHTML = "我就把它改了!谁让你点(打)我呢!";'
      +'console.log("delphi按钮:【调用js】执行了其中的js代码事件");'
      //+'return 12;'//:一旦返回:就不弹出了
    //+'</script>'//:千万不能加,加了就不执行了:跟外部js文件类似,可从外部导入
    ;
  TThread.CreateAnonymousThread(
  procedure begin
    TThread.Synchronize( TThread.Current,
    procedure begin
      Memo1.Lines.Add('TEdgeBrowser控件开始让页面元素执行javascript事件代码......');
      EdgeBrowser1.ExecuteScript(LJs);
    end);
  end).Start;
end;

              Write callback event:

procedure TForm_EdgeBrowser01.EdgeBrowser1ExecuteScript(
  Sender: TCustomEdgeBrowser; AResult: HRESULT;
  const AResultObjectAsJson: string);
begin
  //:回调:TCustomEdgeBrowser.ExecuteScript(const JavaScript: string);
  //:AResult:结果错误码; AResultObjectAsJson:结果对象的Json
  TThread.CreateAnonymousThread(
  procedure begin
    while AResult<>S_OK do sleep(0);
    TThread.Synchronize( nil,
    procedure begin
      Memo1.Lines.Add('EdgeBrowser1执行脚本是否成功(0代表成功):'+IntToStr(AResult));
      Memo1.Lines.Add('EdgeBrowser1执行脚本后返回的Json数值(怪了不回调返回null,bug?!):'+AResultObjectAsJson);
      Memo1.Lines.Add('其实不是的:是因为你的【调用js】中的js没有function返回Json数据!');
    end);
  end).Start;

end;
  •              The essence of callback:

             1.2.4、 TCustomEdgeBrowser.ExecuteScript  // uses Vcl.Edge;

// uses Vcl.Edge;
procedure TCustomEdgeBrowser.ExecuteScript(const JavaScript: string);
begin
  if FWebView <> nil then
    FWebView.ExecuteScript(PChar(JavaScript),
      Callback<HResult, PChar>.CreateAs<ICoreWebView2ExecuteScriptCompletedHandler>(
        function(ErrorCode: HResult; ResultObjectAsJson: PWideChar): HResult stdcall
        begin
          Result := S_OK;
          if Assigned(FOnExecuteScript) then
            FOnExecuteScript(Self, ErrorCode, string(ResultObjectAsJson));
        end));
end;

              1.2.5. As above, the callback of the ExecuteScript method is waiting for the return result of ResultObjectAsJson to be assigned to AResultObjectAsJson in OnExecuteScript, and the error code ErrorCode is assigned to AResult: HRESULT. Therefore, it is essentially a thread synchronization event and requires time to wait.

              1.2.6. Therefore, it is still necessary to put it in a new thread to perform thread synchronization Synchronize. It should be noted that some students habitually use TThread.Current in the current thread. It is best to use nil, because there are many In the threading environment, one thread has a problem, and all others hang up. Give it to the Delphi thread library to uniformly schedule its context and interface with the operating system kernel thread.

 

       Three, paste all the Delphi source code to you

        1.1. For details on the interface, please refer to the previous article "RAD Studio 10.4.1 New Chromium-based Microsoft Edge Browser TEdgeBrowser Control Usage"

         1.2. The code is as follows:

unit uEdgeBrowser01;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Winapi.ActiveX,
  WebView2,  //:Edge的Web视图DLL的静态类型库WebView2.tlb及其关联库的调用:WebView2
  Vcl.Edge,  //:Edge的VCL控件的定义:是对 WebView2.pas 的进一步封装
  Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls
    //, Winapi.ShLwApi :Edge的底层字符串及路由定义
  ;
type
  TForm_EdgeBrowser01 = class(TForm)
    EdgeBrowser1: TEdgeBrowser;
    Panel1: TPanel;
    BitBtn_Navigate: TBitBtn;
    Panel2: TPanel;
    Memo1: TMemo;
    BitBtn_CapturePreview: TBitBtn;
    BitBtn_HandlePostmessage: TBitBtn;
    procedure BitBtn_NavigateClick(Sender: TObject);
    procedure EdgeBrowser1NavigationStarting(Sender: TCustomEdgeBrowser;
      Args: TNavigationStartingEventArgs);
    procedure EdgeBrowser1ContentLoading(Sender: TCustomEdgeBrowser;
      IsErrorPage: Boolean; NavigationID: TUInt64);
    procedure EdgeBrowser1CreateWebViewCompleted(Sender: TCustomEdgeBrowser;
      AResult: HRESULT);
    procedure EdgeBrowser1CapturePreviewCompleted(Sender: TCustomEdgeBrowser;
      AResult: HRESULT);
    procedure BitBtn_CapturePreviewClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser;
      AResult: HRESULT; const AResultObjectAsJson: string);
    procedure EdgeBrowser1WebMessageReceived(Sender: TCustomEdgeBrowser;
      Args: TWebMessageReceivedEventArgs);
    procedure EdgeBrowser1WebResourceRequested(Sender: TCustomEdgeBrowser;
      Args: TWebResourceRequestedEventArgs);
    procedure BitBtn_HandlePostmessageClick(Sender: TObject);
    procedure EdgeBrowser1SourceChanged(Sender: TCustomEdgeBrowser;
      IsNewDocument: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
    Fif_SSL:Boolean;
  end;

var
  Form_EdgeBrowser01: TForm_EdgeBrowser01;

implementation

{$R *.dfm}

procedure TForm_EdgeBrowser01.FormCreate(Sender: TObject);
var LICoreWebView2:ICoreWebView2;
begin
  Memo1.Lines.Add('默认开始初始化(UI设计时的)EdgeBrowser1或初始化动态产生的TEdgeBrowser');
  GetInterface( StringToGUID('{189B8AAF-0426-4748-B9AD-243F537EB46B}'),LICoreWebView2);
  if LICoreWebView2 = EdgeBrowser1.DefaultInterface then
    Memo1.Lines.Add('LICoreWebView2接口TGUID:'+'{189B8AAF-0426-4748-B9AD-243F537EB46B}' );
  //GUIDToString StringToGUID
end;

procedure TForm_EdgeBrowser01.FormShow(Sender: TObject);
begin
  self.Top:=0;  self.Height:=960;
  Memo1.Lines.Add('EdgeBrowser浏览器内部执行的进程ID必须放在其事件中取引用>0的,否则访问的是其基础进程ID(0):'
    +EdgeBrowser1.BrowserProcessID.ToString );
end;

procedure TForm_EdgeBrowser01.BitBtn_NavigateClick(Sender: TObject);
var LHResult_PostWebMessage:HResult;
begin
  if EdgeBrowser1.WebViewCreated then//:必须的,否则接口调用报错:
  begin
    Memo1.Lines.Add('必须EdgeBrowser1.WebViewCreated,否则接口调用报错!'+sLineBreak
      +'有这样一些接口:'+sLineBreak
      +'DefaultInterface: ICoreWebView2'+sLineBreak
      +'ControllerInterface: ICoreWebView2Controller'+sLineBreak
      +'EnvironmentInterface: ICoreWebView2Environment'+sLineBreak
      +'SettingsInterface: ICoreWebView2Settings'+sLineBreak
      );
    Memo1.Lines.Add('TEdgeBrowser:支持异步产生WebView控件:'+sLineBreak
      +'有这样一些方法:'+sLineBreak
      +'TEdgeBrowser.CreateWebView'+sLineBreak
      +'TEdgeBrowser.CloseWebView'+sLineBreak
      +'TEdgeBrowser.CloseBrowserProcess'+sLineBreak
      );
    Memo1.Lines.Add('EdgeBrowser浏览器内部执行的进程ID必须放在其事件中取引用:'
      +EdgeBrowser1.BrowserProcessID.ToString +sLineBreak );
    Memo1.Lines.Add('TEdgeBrowser需要初始化一些参数,以使一些方法或接口生效:' +sLineBreak
      +'EdgeBrowser1.BuiltInErrorPageEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.DefaultContextMenusEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.ZoomControlEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.StatusBarEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.DevToolsEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.DefaultScriptDialogsEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.ScriptEnabled :=true;' +sLineBreak
      +'EdgeBrowser1.WebMessageEnabled :=true;' +sLineBreak
      );

    EdgeBrowser1.BuiltInErrorPageEnabled :=true; //:替代了浏览器内部错误提示
    EdgeBrowser1.ZoomControlEnabled :=true; //:控制用户是否可以影响WebView的缩放
    EdgeBrowser1.DevToolsEnabled :=true; //:控制用户是否能够使用上下文菜单或键盘快捷键打开DevTools窗口

    EdgeBrowser1.StatusBarEnabled :=false;//:控制是否显示状态栏
    EdgeBrowser1.DefaultContextMenusEnabled :=true;//:控制是否在WebView中向用户显示默认上下文菜单
      //:若false:则网页代码中所有涉及Menu的事件将被屏蔽
    {
    EdgeBrowser1.DefaultScriptDialogsEnabled :=true;//:控制在显示JavaScript对话框时是否启动OnScriptDialogOpening
    EdgeBrowser1.ScriptEnabled :=true;//:控制是否在以后的所有导航视图中启用JavaScript的执行
      //:特别注意:这两个属性:只要引用无论false或true,
        //,网页下载的原生js将不在生效:由代码控制
        //:ScriptEnabled :并不影响执行方法ExecuteScript(const JavaScript: string);
    //}
    EdgeBrowser1.WebMessageEnabled :=true;//:必须的,否则接口PostWebMessageAsString调用报错:
    //(*
    LHResult_PostWebMessage
      :=EdgeBrowser1.DefaultInterface.PostWebMessageAsString(
        PWideChar('{ICoreWebView2:true}') ) ;//:0接口函数执行成功 -1失败
    if LHResult_PostWebMessage> -1 then
      Memo1.Lines.Add('开始访问TEdgeBrowser的接口对象'
        +IntToStr(LHResult_PostWebMessage) +sLineBreak
        +'调用JavaScript也是类似的方式ExecuteScript()' +sLineBreak
        );
      //:开始访问TEdgeBrowser的接口对象
    //*)
    TThread.CreateAnonymousThread(
      procedure
      begin
        TThread.Synchronize( nil,
        procedure //var AHTMLContent: string;
        begin //EdgeBrowser1.NavigateToString(AHTMLContent);
          if EdgeBrowser1.Navigate(//:如果返回了错误码:=true,否则:=false
            'https://www.cpuofbs.com/index.html' )=false then
          //if EdgeBrowser1.Navigate(ExtractFilePath(ParamStr(0))+ 'mytest.html')=false then
          Memo1.Lines.Add('开始请求浏览网页!' +sLineBreak );

        end);
      end
    ).Start;//}
  end;
  //EdgeBrowser1.Navigate('https://www.cpuofbs.com/index.html' );
    //:养成使用线程的习惯:b/s的客户端:"浏览器"和我们的c/s客户端App一样
      //:否则"浏览器"的UI也会出现“好像有点卡嘛”的不良UE体验
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1ContentLoading(
  Sender: TCustomEdgeBrowser; IsErrorPage: Boolean; NavigationID: TUInt64);
begin
  Memo1.Lines.Add('TEdgeBrowser组件NavigationID:'+IntToStr(NavigationID)
    +',SizeRatio'+EdgeBrowser1.SizeRatio.ToString +sLineBreak
    +':正在调取页面内容'+EdgeBrowser1.LocationURL +sLineBreak);
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1CreateWebViewCompleted(
  Sender: TCustomEdgeBrowser; AResult: HRESULT);
begin
//
end;

procedure TForm_EdgeBrowser01.BitBtn_CapturePreviewClick(Sender: TObject);
begin
  if EdgeBrowser1.WebViewCreated then
  begin
    EdgeBrowser1.ZoomFactor:=100/100;
    EdgeBrowser1.CapturePreview(
      System.SysUtils.ExtractFilePath(
        System.ParamStr(0))+'CapturePreview01.png',PNG);
  end;

end;

procedure TForm_EdgeBrowser01.EdgeBrowser1CapturePreviewCompleted(
  Sender: TCustomEdgeBrowser; AResult: HRESULT);
begin
  Memo1.Lines.Add('TEdgeBrowser组件CapturePreview输出呈现部分的图片:CapturePreview01.png ,AResult='+IntToStr(AResult)+sLineBreak );
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1NavigationStarting(
  Sender: TCustomEdgeBrowser; Args: TNavigationStartingEventArgs);
var Lname,Lvalue : PWideChar;
  LHeaders: ICoreWebView2HttpRequestHeaders;
  Literator: ICoreWebView2HttpHeadersCollectionIterator;
  LhasNext, LhasCurrent: Integer;
  Luri: PWideChar;
  Lnavigation_id: Largeuint;
begin

  Memo1.Lines.Add('TEdgeBrowser组件在执行Navigate时,触发NavigationStarting准备开始浏览网页!'+sLineBreak );
  Args.ArgsInterface.Get_uri(Luri);//:获取当前浏览的网页的uri
  Fif_SSL:= string(Luri).Contains('https');
  if Fif_SSL=true then
  begin
    Memo1.Lines.Add('您当前浏览的网页是https安全链接!'+sLineBreak );
//    Args.ArgsInterface.Set_Cancel(0);
//    ShowMessage('您当前浏览的网页是https安全链接,请放心使用!');
  end else
  begin
    Memo1.Lines.Add('您当前浏览的网页不是https安全链接!'+sLineBreak );
//    Args.ArgsInterface.Set_Cancel(-1);
//    ShowMessage('您当前浏览的网页不是https安全链接,本程序禁止运行!');
  end;

  Args.ArgsInterface.Get_RequestHeaders(LHeaders);
  LHeaders.GetIterator(Literator);

  Memo1.Lines.BeginUpdate;
  Literator.MoveNext(LhasNext);
  while LhasNext<>0 do
  begin
    Literator.Get_HasCurrentHeader(LhasCurrent);
    Literator.GetCurrentHeader(Lname,Lvalue);
    Memo1.Lines.AddPair('头信息LhasNext:'+LhasNext.ToString+',LhasCurrent:'+LhasCurrent.ToString+',名称:'+Lname,',值:'+Lvalue);

    Literator.MoveNext(LhasNext);
  end;
  Memo1.Lines.Add('请求的uri:'+Luri);
  Memo1.Lines.Add('navigation_id:'+Lnavigation_id.ToString);
  Memo1.Lines.Add(sLineBreak);

  Memo1.Lines.EndUpdate;
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1SourceChanged(
  Sender: TCustomEdgeBrowser; IsNewDocument: Boolean);
begin
  if IsNewDocument then Memo1.Lines.Add('您打开的新的文档进行浏览!');
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1WebResourceRequested(
  Sender: TCustomEdgeBrowser;
  Args: TWebResourceRequestedEventArgs);
//:交互式的事件,除非页面元素的事件的javascript代码触发了它:
var
  LRequest: ICoreWebView2WebResourceRequest;
  LMethod: PWideChar;
  LResponse: ICoreWebView2WebResourceResponse;
begin
  Args.ArgsInterface.Get_Request(LRequest);//:拿到请求接口
    LRequest.Get_Method(LMethod);
    Memo1.Lines.Add('请求的Method:'+LMethod);
  Args.ArgsInterface.Get_Response(LResponse);//:拿到响应接口

end;

procedure TForm_EdgeBrowser01.EdgeBrowser1WebMessageReceived(
  Sender: TCustomEdgeBrowser;
  Args: TWebMessageReceivedEventArgs);
//:交互式的事件,除非页面元素的事件的javascript代码postMessage触发了它:
(*//:比如:
<!DOCTYPE html>
<html>
<body>
    <p onclick="handleClick()">发送消息</p>
    <script>
        function handleClick() {
            window.chrome.webview.postMessage({ data: 'Message from Edge Chromium', url: window.document.URL });
        }
    </script>
</body>
</html>
*)
var
  LSource: PWideChar;
  LwebMessageAsJson: PWideChar;
  LwebMessageAsString: PWideChar;
begin
  Args.ArgsInterface.Get_Source(LSource);
    Memo1.Lines.Add('接收到的Web消息-资源:'+LSource);
  Args.ArgsInterface.TryGetWebMessageAsString(LwebMessageAsString);
    Memo1.Lines.Add('尝试接收的Web消息-字符串:'+LwebMessageAsString);

  Args.ArgsInterface.Get_webMessageAsJson(LwebMessageAsJson);
    Memo1.Lines.Add('接收到的Web消息-Json数据:'+LwebMessageAsJson);
  MessageBox(Handle, LwebMessageAsJson, PChar('牵引软件-提醒您:'), MB_OK);
    //:window.chrome.webview.postMessage的url请求资源的路径Rest要正确否则不回调:...
    //AddScriptToExecuteOnDocumentCreated
end;

procedure TForm_EdgeBrowser01.EdgeBrowser1ExecuteScript(
  Sender: TCustomEdgeBrowser; AResult: HRESULT;
  const AResultObjectAsJson: string);
begin
  //:回调:TCustomEdgeBrowser.ExecuteScript(const JavaScript: string);
  //:AResult:结果错误码; AResultObjectAsJson:结果对象的Json
  TThread.CreateAnonymousThread(
  procedure begin
    while AResult<>S_OK do sleep(0);
    TThread.Synchronize( nil,
    procedure begin
      Memo1.Lines.Add('EdgeBrowser1执行脚本是否成功(0代表成功):'+IntToStr(AResult));
      Memo1.Lines.Add('EdgeBrowser1执行脚本后返回的Json数值(怪了不回调返回null,bug?!):'+AResultObjectAsJson);
      Memo1.Lines.Add('其实不是的:是因为你的【调用js】中的js没有function返回Json数据!');
    end);
  end).Start;

end;

procedure TForm_EdgeBrowser01.BitBtn_HandlePostmessageClick(Sender: TObject);
var LJs:string;
begin
  LJs:=
    //'<script type="text/javascript">'//:千万不能加,加了就不执行了:跟外部js文件类似,可从外部导入
      //'return 12;'+//:一旦返回:就不弹出了:
       'window.alert("既然你让我弹出,那你一点’‘确定’‘我就:");'
       (*'webview.contentWindow.postMessage.postMessage('
			   +'{ data: "既然你让我弹出,那你一点’‘确定’‘我就:", , "*" }'
				 +');'//*)
      +'document.getElementById("mytestclick").innerHTML = "我就把它改了!谁让你点(打)我呢!";'
      +'console.log("delphi按钮:【调用js】执行了其中的js代码事件");'
      //+'return 12;'//:一旦返回:就不弹出了
    //+'</script>'//:千万不能加,加了就不执行了:跟外部js文件类似,可从外部导入
    ;
  TThread.CreateAnonymousThread(
  procedure begin
    TThread.Synchronize( TThread.Current,
    procedure begin
      Memo1.Lines.Add('TEdgeBrowser控件开始让页面元素执行javascript事件代码......');
      EdgeBrowser1.ExecuteScript(LJs);
    end);
  end).Start;
end;


end.

 Attachment: Related blog posts of this blog:

         1. "RAD Studio 10.4.1 new Chromium-based Microsoft Edge browser TEdgeBrowser control usage"

         2. "Delphi Restful Interaction between Client JavaScript and Middleware Server"

 If you like it, just click like and favorite below, so that you can watch the next sharing:

Guess you like

Origin blog.csdn.net/pulledup/article/details/109934357