Recent

Author Topic: Minimum code for implementing WebView (deprecated) or WKWebView  (Read 42848 times)

Zoë

  • New Member
  • *
  • Posts: 25
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #45 on: January 10, 2022, 07:06:41 pm »
https://github.com/genericptr/MacOS_11_0/tree/master/webkit

Ryan updated his parser and posted macOS 11 headers, but they haven't been merged yet.  Looks like they're declaring cblock callbacks now, so you can grab the relevant definitions from there.

Quote
Now, I am not too much into Apple API but I guess a try at CBlock callback would be

That looks correct to me, but definitely double check it with the headers above.

Quote
Ideally it would be great if the completionHandler code could be closure like... Or a sub procecedure? But I do not think CBlock allows for this?

Unfortunately, no, you have to use an object's method.  Hopefully the cblock/closure code can be unified in the future, but the contractor we have working on adding anonymous methods doesn't have a Mac, so it'll have to wait until it's merged and someone else can take a crack at it.

Quote
But then to actually use with the non-fixed FPC source casting would be necessary?

The way I've done it in the past was to assign the method to a local variable that has the correct cblock declaration, and then pass that variable in with an OpaqueCBlock cast.

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #46 on: January 11, 2022, 01:20:52 pm »
Hi Zoë

Thank you very much.

Following your link
https://github.com/genericptr/MacOS_11_0/tree/master/webkit

I am now using:
Code: Pascal  [Select][+][-]
  1. type
  2.   WKWebViewEvaluateJavascriptCallback = reference to procedure(param1: id; error: NSError); cblock; cdecl;
  3.  

In my class I defined *methods*:
 
Code: Pascal  [Select][+][-]
  1.  // bla bla bla
  2.   public
  3.     function GetDocumentAsStr: string;
  4.     procedure GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cblock; cdecl;
  5.   end;
  6.  


In GetDocumentAsStr I have (simplified):
Code: Pascal  [Select][+][-]
  1. function TmsdvViewerCocoaWKWebView.GetDocumentAsStr: string;
  2. var
  3.   TmpJavaScriptCodeNSStr: NSString;
  4.   TmpFuncCallbackRefVar: WKWebViewEvaluateJavascriptCallback;
  5. begin
  6.       TmpJavaScriptCodeNSStr := msMac_StrToNSStr('document.documentElement.outerHTML');
  7.       TmpFuncCallbackRefVar := @GetDocumentAsStr_JavascriptCallback;
  8.       FWebBrowser.FWebView_CocoaWKWebView.evaluateJavaScript_completionHandler(
  9.         TmpJavaScriptCodeNSStr,
  10.         OpaqueCBlock(TmpFuncCallbackRefVar)
  11.       );
  12.  

However I am getting errors for:
Code: Pascal  [Select][+][-]
  1. procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cblock; cdecl;
Code: Pascal  [Select][+][-]
  1. procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cdecl;
  2.  
=
Quote
Error: Function header doesn't match the previous declaration "GetDocumentAsStr_JavascriptCallback(id;NSError) is block; CDecl;"

while
Code: Pascal  [Select][+][-]
  1. procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError);
  2.  
=
Quote
Error: Calling convention doesn't match forward

If anyone has any ideas what to try next... Or if I am doing something wrong :)
« Last Edit: January 11, 2022, 01:23:09 pm by MISV »

Zoë

  • New Member
  • *
  • Posts: 25
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #47 on: January 11, 2022, 09:10:04 pm »
Quote
However I am getting errors for:
Code: Pascal  [Select][+][-]
  1. procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cblock; cdecl;

Remove the 'cblock' from here.  The cblock is part of the variable/argument declaration, not something you need to flag your own methods with.

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #48 on: January 12, 2022, 12:08:42 am »
Hi Zoë

Already tried.

Code: Pascal  [Select][+][-]
  1. procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cdecl;

gives error

Quote
Error: Function header doesn't match the previous declaration "GetDocumentAsStr_JavascriptCallback(id;NSError) is block; CDecl;"

Zoë

  • New Member
  • *
  • Posts: 25
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #49 on: January 12, 2022, 12:40:22 am »
You need to remove 'cblock' from everywhere in your code except the variable declaration:

Code: [Select]
type
  WKWebViewEvaluateJavascriptCallback = reference to procedure(param1: id; error: NSError); cblock; cdecl; // <<< SHOULD BE HERE
 
type
  TmsdvViewerCocoaWKWebView = ...
  public
    function GetDocumentAsStr: string;
    procedure GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); cdecl; // << SHOULD _NOT_ BE HERE
  end;
 
function TmsdvViewerCocoaWKWebView.GetDocumentAsStr: string;
var
  TmpJavaScriptCodeNSStr: NSString;
  TmpFuncCallbackRefVar: WKWebViewEvaluateJavascriptCallback;
begin
  TmpJavaScriptCodeNSStr := msMac_StrToNSStr('document.documentElement.outerHTML');
  TmpFuncCallbackRefVar := @GetDocumentAsStr_JavascriptCallback;
  FWebBrowser.FWebView_CocoaWKWebView.evaluateJavaScript_completionHandler(
    TmpJavaScriptCodeNSStr,
    OpaqueCBlock(TmpFuncCallbackRefVar)
    );
 end;

procedure TmsdvViewerCocoaWKWebView.GetDocumentAsStr_JavascriptCallback(param1: id; error: NSError); // << SHOULD NOT BE HERE
begin
  //
end

For the last one, 'cdecl' shouldn't be necessary either since the compiler should grab it from the class declaration, though I generally use {$MODE DELPHI} so I'm not positive on that for other modes.

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #50 on: January 12, 2022, 11:58:56 am »
Thank you. Compilation works now. I will try out later if code crashes :D

One more question...

From
https://github.com/genericptr/MacOS_11_0/blob/master/webkit/WKWebView.inc

I see:
Code: Pascal  [Select][+][-]
  1. procedure setCustomUserAgent(newValue: NSString); message 'setCustomUserAgent:'; { available in macos 10.11, ios 9.0 }
  2. function customUserAgent: NSString; message 'customUserAgent'; { available in macos 10.11, ios 9.0 }

Does anyone know how API binding works on Mac?

Like if I add the above to my own WKWebView descendant... And user runs it on Mac OS 10.10 ... Will the executable not start?

Or is it sufficient that I check MacOS version before calling setCustomUserAgent?

Zoë

  • New Member
  • *
  • Posts: 25
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #51 on: January 12, 2022, 09:46:02 pm »
I think that standalone functions you need to load dynamically, but methods of Cocoa objects will be fine as long as you check the OS version before calling them.  Though macOS 10.11 is a reasonable lower bound nowadays anyway.  That's what we use for our app and we don't get any pushback about it (though we do have an older version that supports back to 10.6 available).

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #52 on: January 13, 2022, 01:16:01 am »
Quote
Or is it sufficient that I check macOS version before calling setCustomUserAgent?

You could do something like this to avoid undesired outcomes:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   aSEL : SEL;
  4. begin
  5.     // Check whether OS version responds to this selector
  6.     aSEL := objcselector('operatingSystemVersion');
  7.     if NSProcessInfo.processInfo.respondsToSelector(aSEL) then
  8.       ProcessInfo
  9.     // Otherwise fallback to the deprecated Gestalt Manager
  10.     else
  11.       GestaltInfo;
  12. end;

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #53 on: January 13, 2022, 01:13:39 pm »
Quick update: Javascript callback works.

New problem. I am pulling in all headers more or less because I need to do stuff.

However, I am encountering a circular referencing problem.

Declaration for

WKUserContentController references in its protocol declaration WKScriptMessageHandlerProtocol
and
WKScriptMessageHandlerProtocol references in its protocol declaration WKUserContentController

Not sure how to handle that.

Man... if those headers were implemented in FPC/Lazarus getting WKWebView to fully work would take estimated 1/20 of the time :D


trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #54 on: January 13, 2022, 10:48:00 pm »
Man... if those headers were implemented in FPC/Lazarus getting WKWebView to fully work would take estimated 1/20 of the time :D

Have you considered Ryan's conversion of the Cocoa headers for the macOS 11 SDK?

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #55 on: January 13, 2022, 11:33:10 pm »
I am manually copying in parts. Do you suggest I download the files and put them in a shared code library and try get Lazarus to use them? (Could not recompile FPC source)

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #56 on: January 13, 2022, 11:55:28 pm »
In the past I've simply copied Cocoa headers into my applications when I've needed to change/omit/add to the existing Cocoa headers (and removed the framework link directives).

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #57 on: January 14, 2022, 10:43:07 am »
Maybe that had been better. But well, seems like no matter the solution one uses something trippy happens. But seems like a good idea, but not sure I want to to change now unless strictly necessary. It works OK copying in all headers. And then some day FPC team wants to integrate new headers I can comment it out.

But still... the problem is confusing:


Code: Pascal  [Select][+][-]
  1. //--
  2. // WKUserContentController.inc
  3. //--
  4. type
  5.   WKUserContentController = objcclass external (NSObject, NSSecureCodingProtocol)
  6.   public
  7.     function userScripts: NSArray; message 'userScripts';
  8.     procedure addUserScript (userScript: WKUserScript); message 'addUserScript:';
  9.     procedure removeAllUserScripts; message 'removeAllUserScripts';
  10.     procedure addScriptMessageHandler_contentWorld_name (scriptMessageHandler: WKScriptMessageHandlerProtocol; world: WKContentWorld; name: NSString); message 'addScriptMessageHandler:contentWorld:name:'; { available in macos 11.0, ios 14.0 }
  11.     procedure addScriptMessageHandlerWithReply_contentWorld_name (scriptMessageHandlerWithReply: WKScriptMessageHandlerWithReplyProtocol; contentWorld: WKContentWorld; name: NSString); message 'addScriptMessageHandlerWithReply:contentWorld:name:'; { available in macos 11.0, ios 14.0 }
  12.     procedure addScriptMessageHandler_name (scriptMessageHandler: WKScriptMessageHandlerProtocol; name: NSString); message 'addScriptMessageHandler:name:';
  13.     procedure removeScriptMessageHandlerForName_contentWorld (name: NSString; contentWorld: WKContentWorld); message 'removeScriptMessageHandlerForName:contentWorld:'; { available in macos 11.0, ios 14.0 }
  14.     procedure removeScriptMessageHandlerForName (name: NSString); message 'removeScriptMessageHandlerForName:';
  15.     procedure removeAllScriptMessageHandlersFromContentWorld (contentWorld: WKContentWorld); message 'removeAllScriptMessageHandlersFromContentWorld:'; { available in macos 11.0, ios 14.0 }
  16.     procedure removeAllScriptMessageHandlers; message 'removeAllScriptMessageHandlers'; { available in macos 11.0, ios 14.0 }
  17.     procedure addContentRuleList (contentRuleList: WKContentRuleList); message 'addContentRuleList:'; { available in macos 10.13, ios 11.0 }
  18.     procedure removeContentRuleList (contentRuleList: WKContentRuleList); message 'removeContentRuleList:'; { available in macos 10.13, ios 11.0 }
  19.     procedure removeAllContentRuleLists; message 'removeAllContentRuleLists'; { available in macos 10.13, ios 11.0 }
  20.     { Adopted protocols }
  21.     procedure encodeWithCoder (coder: NSCoder); message 'encodeWithCoder:';
  22.     function initWithCoder (coder: NSCoder): id; message 'initWithCoder:';
  23.     class function supportsSecureCoding: objcbool; message 'supportsSecureCoding';
  24.   end;
  25. type
  26.   WKUserContentControllerPtr = ^WKUserContentController;
  27. //--
  28. // WKScriptMessageHandler.inc
  29. //--
  30. type
  31.   WKScriptMessageHandlerProtocol = objcprotocol external name 'WKScriptMessageHandler' (NSObjectProtocol)
  32.   required
  33.     procedure userContentController_didReceiveScriptMessage (userContentController: WKUserContentController; message_: WKScriptMessage); message 'userContentController:didReceiveScriptMessage:';
  34.   end;
  35.  

Can't solve the circular reference between WKUserContentController and and WKScriptMessageHandlerProtocol



One additional oddness I have found is that copy from the updated headers I see code like this

Code: Pascal  [Select][+][-]
  1. type
  2.   WKScriptMessageHandlerProtocolPtr = ^WKScriptMessageHandlerProtocol;
  3.   WKScriptMessageHandlerProtocol = objcprotocol external name 'WKScriptMessageHandler' (NSObjectProtocol)
  4.   ...
  5.  

But when I compile Lazarus/FPC will not accept that and forces me to reverse order

Code: Pascal  [Select][+][-]
  1. type
  2.   WKScriptMessageHandlerProtocol = objcprotocol external name 'WKScriptMessageHandler' (NSObjectProtocol)
  3.   ...
  4.   WKScriptMessageHandlerProtocolPtr = ^WKScriptMessageHandlerProtocol;
  5.  

Not sure if the problem is related with some kind of forwards
« Last Edit: January 14, 2022, 10:47:49 am by MISV »

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #58 on: January 14, 2022, 10:49:28 am »
Found what I THOUGHT was solution in

https://github.com/genericptr/MacOS_11_0/blob/557d8f835b5591b8c43b820a8554185c0e402f2e/DefinedClassesWebKit.pas

DefinedClasses.inc


So examples
Code: Pascal  [Select][+][-]
  1.   WKScriptMessageHandlerProtocol = objcprotocol external name 'WKScriptMessageHandler';
  2.   // above forward for: WKScriptMessageHandlerProtocol = objcprotocol external name 'WKScriptMessageHandler' (NSObjectProtocol)
  3.  
  4.   WKUserContentController = objcclass external;
  5.   // above forward for: WKUserContentController = objcclass external (NSObject, NSSecureCodingProtocol)
  6.  


I am flipping inside right now. Why the **** does this work for the headers, but if predefine/forward declarations like above I get

Quote
Error: Duplicate identifier "xxxx"
Hint: Identifier already defined in UmsXXX.pas at line xxx

I actually think getting WKWebView fully working with all features would take like 1/50 of the time without all these problems  :o
« Last Edit: January 14, 2022, 11:12:20 am by MISV »

MISV

  • Hero Member
  • *****
  • Posts: 791
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #59 on: January 15, 2022, 11:20:35 am »
I am going to solve this "broken forwards of all kinds not working in my Lazarus" + "circular referencing" problems by...

Simply leaving out those declarations. I think that will work as long as I do not need to call them. At least I can compile then. Will need to see if causes problems runtime.

Do you agree this most likely will work? (i.e. I can only test on my own Mac, so if you have experience with it then do please let me know)

It will do as a temporary solution, so I can continue work and possibly also release.

 

TinyPortal © 2005-2018