Recent

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

MISV

  • Hero Member
  • *****
  • Posts: 792
To get a better grib about how Cocoa works with LCL I decided I would like to show WebView in a control. I am aware Phil made something which I also used as a starting point. However - it seems when using widgetset compatible code things are a little different - or I am messing up badly. Either way, good learning experience.



So I have this

Code: Pascal  [Select][+][-]
  1. TmyWebBrowserCocoa = class(TWinControl)
  2. protected
  3. public
  4.   constructor Create(AOwner: TComponent);
  5.   destructor Destroy; override;
  6.   procedure Init_WebView;
  7.   procedure Navigate(const AURL: string):
  8. end;
  9.  
  10. TmyWebBrowserCocoaDelegate = objcclass(NSObject)
  11. public
  12.   // implement those we need
  13. end;
  14.  
  15. constructor TmyWebBrowserCocoa.Create(AOwner: TComponent);
  16. begin
  17.   inherited Create(AOwner);
  18. end;
  19.  
  20. procedure TmyWebBrowserCocoa.Init_WebView;
  21. var
  22.   TmpWebView: WebView;
  23.   TmpDelegate: TmyWebBrowserCocoaDelegate;
  24.   TmpParams: TCreateParams;
  25. begin
  26.   TmpParams.WndParent := Self.Handle;
  27.   TmpParams.X := 0;
  28.   TmpParams.Y := 0;
  29.   TmpParams.Width := Self.ClientWidth;
  30.   TmpParams.Width := Self.ClientHeight;
  31.   TmpWebView := WebView(NSView(WebView.alloc).lclInitWithCreateParams(TmpParams));
  32.   TmpDelegate := TmyWebBrowserCocoaDelegate.alloc.init;
  33.   TmpWebView.setFrameLoadDelegate(TmpDelegate);
  34. end;
  35.  
  36. destructor TmyWebBrowserCocoa.Destroy;
  37. begin
  38.   WebView(Self.Handle).frameLoadDelegate.release;
  39.   NSObject(Self.Handle).release;
  40.   inherited Destroy;
  41. end;
  42.  
  43. procedure TmyWebBrowserCocoa.Navigate(const AURL: string);
  44. var
  45.   ANSURL : NSURL;
  46.   ANSReq : NSURLRequest;
  47. begin
  48.   // to keep simple we are testing using https://example.com to avoid any charset and encoding problems
  49.   ANSURL := NSURL.URLWithString(NSSTR(PAnsiChar(AURL)));
  50.   ANSReq := NSURLRequest.RequestWithURL(ANSURL);
  51.   WebView(Self.Handle).mainFrame.loadRequest(ANSReq); // SIGABRT here
  52. end;
  53.  

Created and called like this

Code: Pascal  [Select][+][-]
  1. var
  2.   WebBrowser: TmyWebBrowserCocoa
  3. begin
  4.   FWebBrowser := TmyWebBrowserCocoa.Create(FBrowserHostParent);
  5.   FWebBrowser.Parent :=FBrowserHostParent;
  6.   FWebBrowser.Visible := False;
  7.   FWebBrowser.Align := alClient;
  8.   FWebBrowser.Init_WebView;
  9.   FWebBrowser.Visible := True;
  10.   FWebBrowser.Navigate('https://example.com/');
  11. end;



However, I am getting SIGABRT inside navigate... probably a handle issue
« Last Edit: July 26, 2018, 12:28:53 pm by MISV »

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Minimum code for implementing WebView
« Reply #1 on: July 24, 2018, 03:33:49 pm »
To get a better grib about how Cocoa works with LCL I decided I would like to show WebView in a control. I am aware Phil made something which I also used as a starting point. However - it seems when using widgetset compatible code things are a little different - or I am messing up badly. Either way, good learning experience.

TWebBrowser is "widgetset compatible code".

https://macpgmr.github.io

What are you trying to do that isn't already covered in TWebBrowser?

MISV

  • Hero Member
  • *****
  • Posts: 792
Re: Minimum code for implementing WebView
« Reply #2 on: July 24, 2018, 03:45:31 pm »
To get a better grib about how Cocoa works with LCL I decided I would like to show WebView in a control. I am aware Phil made something which I also used as a starting point. However - it seems when using widgetset compatible code things are a little different - or I am messing up badly. Either way, good learning experience.

TWebBrowser is "widgetset compatible code".

https://macpgmr.github.io

What are you trying to do that isn't already covered in TWebBrowser?

I explicit noted in my post your code was "widgetset compatible code" unlike mine :)

I am merely trying to learn where I have made an error in making a non-widgetset-compatible webview in cocoa.
« Last Edit: July 24, 2018, 03:47:28 pm by MISV »

MISV

  • Hero Member
  • *****
  • Posts: 792
Re: Minimum code for implementing WebView
« Reply #3 on: July 24, 2018, 11:50:30 pm »
Okay - I got it working.

Essentially not using the handle stuff but instead keep references (e.g. FWebView) and use them helped + some fixes along the way.

MISV

  • Hero Member
  • *****
  • Posts: 792
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #4 on: July 26, 2018, 12:30:35 pm »
Quick note: You can resize your webview when the parent-wincontrol resize using setFrameOrigin + setFrameSize

One problem though...

Seems WebKit has been deprecated for a while in favour WKWebView, so WebKit support may be ending in a later macOS version...

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #5 on: July 26, 2018, 02:04:32 pm »
Quick note: You can resize your webview when the parent-wincontrol resize using setFrameOrigin + setFrameSize

One problem though...

Seems WebKit has been deprecated for a while in favour WKWebView, so WebKit support may be ending in a later macOS version...

The WebView class has been deprecated in favor of the WKWebView class. The WebKit framework has not been deprecated.

https://developer.apple.com/documentation/webkit/wkwebview

FPC's ancient WebKit unit does not include the newer WKWebView class, but the MacOS_10_10 parsed headers here does:

https://github.com/genericptr

« Last Edit: July 26, 2018, 02:08:45 pm by Phil »

wittbo

  • Full Member
  • ***
  • Posts: 150
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #6 on: June 05, 2021, 01:38:52 pm »
i find your approach very interesting to understand what is really happening and what has to be done for it. i tried to reproduce your example (see attachment). i have a form with 2 buttons. Click on the left button should create and initialize the WebView, click on the second button should load a web page into the WebView.

The program compiles without errors. But at runtime nothing happens, neither after click on the first button nor after click on the second button, no error message, no crash, nothing.

I think it must have something to do with the handle of the parent view. Using XCode and ObjectiveC/Swift, I have to define the WebView as a subview in the parent view (....addSubview()). How does this happen in Pascal? Do you have any idea?

-wittbo-
-wittbo-
MBAir with MacOS 10.14.6 / Lazarus 2.2.4
MacStudio with MacOS 13.0.1 / Lazarus 2.2.4

wittbo

  • Full Member
  • ***
  • Posts: 150
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #7 on: June 07, 2021, 12:44:49 pm »
Some additional information:

... last line creation code:
...
myWebBrowserCocoa.Visible := True;
System is hanging.

- commenting this line and executing the loading code:
...
WebView(Self.Handle).mainFrame.loadRequest(ANSReq)
System crashes.

So, MISV, can you remember, what were the necessary tricks to get it working?
-wittbo-
MBAir with MacOS 10.14.6 / Lazarus 2.2.4
MacStudio with MacOS 13.0.1 / Lazarus 2.2.4

wittbo

  • Full Member
  • ***
  • Posts: 150
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #8 on: June 07, 2021, 08:28:42 pm »
Done!   Here is the full working demo program.  8-)

Based on the TWebBrowser component package of Phil (s.a.); really minimum code, no delegate code, only the essential code for creating the webview and loading an example https page into it.

And - in contrast to the statement of MISV above - you will really need the Handle stuff. And the most important statement is this mystic RegisterWSComponent, which -for me- does a mapping of the Cocoa specific WSWincontrol class into the general WinControl class of the webbrowser component. But I have only a poor idea of what RegisterWSComponent really does.

Without that I could not get this to work, especially the code fragments of MISV (s.a.) didn't really work.

My next steps will be:
- delete the webview component under program control
- convert the code to use the new WKWebView
-wittbo-
MBAir with MacOS 10.14.6 / Lazarus 2.2.4
MacStudio with MacOS 13.0.1 / Lazarus 2.2.4

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #9 on: June 08, 2021, 02:55:58 am »
Thanks for sharing wittbo!

wittbo

  • Full Member
  • ***
  • Posts: 150
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #10 on: June 08, 2021, 06:43:32 pm »
Finished work. Try the demo.
Implemented close of the webview
Implemented the newer WKWebView.

The latter wasn't a real problem, since the cocoaint webkit unit now includes the wkwebview.inc include. For creating and closing no change. Loading of a page is a little bit easier, there is no mainframe necessary. WKWebView has some new magnification methods to read and set the magnification of the page.

The demo program contains both WebView and WKWebView methods; you can choose between them by setting the compiler defines at line 15/16.

I will use the WKWebView to integrate a PDF Viewer into my app and it's really quite easy, you only need the URL-variant of the PDF file.

If anyone knows something similar for MS Windows (10 or newer), I would be interested as well.

BTW: Something seems to be wrong with line 16 of .../wkwebview.inc:
{$if defined(TARGET_OS_IPHONE)defined(interface)defined(WKWebView)defined(UIView)}
When loading this file into the Lazarus ide, you get an error at line 16: "Error: operator missing". Since I could compile and run my program anyway, I did not pursue the message further.
-wittbo-
MBAir with MacOS 10.14.6 / Lazarus 2.2.4
MacStudio with MacOS 13.0.1 / Lazarus 2.2.4

MISV

  • Hero Member
  • *****
  • Posts: 792
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #11 on: June 11, 2021, 09:12:20 am »
Just for completeness here is my original code:


I have a TWinControl hosting the browser contorl


So when parent control resizes I do

Code: Pascal  [Select][+][-]
  1.   if FWebView_Cocoa <> nil then
  2.     begin
  3.       TmpPoint.x := Self.Left;
  4.       TmpPoint.y := Self.Top;
  5.       FWebView_Cocoa.setFrameOrigin(TmpPoint);
  6.       TmpSize.width := Self.ClientWidth;
  7.       TmpSize.height := Self.ClientHeight;
  8.       FWebView_Cocoa.setFrameSize(TmpSize);
  9.  

To initialize I do:

Code: Pascal  [Select][+][-]
  1.   if FWebView_Cocoa = nil then
  2.     begin
  3. //(*
  4.       TmpParams.WndParent := Self.Handle;
  5.       TmpParams.X := 0;
  6.       TmpParams.Y := 0;
  7.       TmpParams.Width := Self.ClientWidth;
  8.       TmpParams.Height := Self.ClientHeight;
  9.       TmpParams.Style := WS_VISIBLE;
  10.       FWebView_Cocoa := WebView( NSView(WebView.alloc).lclInitWithCreateParams(TmpParams) );
  11.  
  12.  
  13.       FDelegate_Cocoa_Frame := Tmsdv_cocoanative_WebBrowserCocoaDelegate_Frame.alloc.init;
  14.       FDelegate_Cocoa_Frame.FBrowserCtrlRef := Self;
  15.       FWebView_Cocoa.setFrameLoadDelegate(FDelegate_Cocoa_Frame);
  16.  


Then I have this:

Code: Pascal  [Select][+][-]
  1.   Tmsdv_cocoanative_WebBrowserCocoaDelegate_Frame = objcclass(NSObject)
  2.   private
  3.     FBrowserCtrlRef: TmsdvWebBrowserCocoa;
  4.   public
  5.   public
  6.     procedure webView_didFinishLoadForFrame(sender: WebView; frame: WebFrame); override;
  7.     procedure webView_didStartProvisionalLoadForFrame(sender: WebView; frame: WebFrame); override;
  8.     procedure webView_didFailProvisionalLoadWithError_forFrame(sender: WebView; error: NSError; frame: WebFrame); override;
  9.     procedure webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(webView_: WebView; actionInformation: NSDictionary; request: NSURLRequest; frameName: NSString; listener: WebPolicyDecisionListenerProtocol); override;
  10.   end;
  11.  


Hope this helps


(Great work if wkwebview can be implemented now! I wonder if one needs ti support both for newer/older Mac OS and how to select between them)


trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #12 on: June 11, 2021, 09:19:57 am »
* WKWebView requires macOS 10.10+
* WebView is available in macOS 10.3–10.14

As for selecting between them, something like this:

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 // procedure
  9.     // Otherwise fallback to the deprecated Gestalt Manager
  10.     else
  11.       GestaltInfo; // procedure
  12. end;
« Last Edit: June 11, 2021, 09:31:19 am by trev »

wittbo

  • Full Member
  • ***
  • Posts: 150
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #13 on: July 31, 2021, 11:32:18 am »
I have done some experiments with WKWebView in the meantime. The minimal use of the methods to open a WKWebView and load a web page are even a bit easier than with the WebView. However, I am not getting anywhere with the implementation of the delegate methods to check the loading process. With WebView you simply had to create an objcclass(NSObject) for the desired delegate methods and pass it to the Webview with setFrameLoadDelegate. This doesn't work with WKWebView now (or I didn't understand it). Here I need a WKNavigationDelegate protocol object. And that's where my options end, as I don't know how to implement this. Maybe someone has an idea?
-wittbo-
MBAir with MacOS 10.14.6 / Lazarus 2.2.4
MacStudio with MacOS 13.0.1 / Lazarus 2.2.4

MISV

  • Hero Member
  • *****
  • Posts: 792
Re: Minimum code for implementing WebView (deprecated) or WKWebView
« Reply #14 on: August 17, 2021, 11:18:08 am »
I will try return to this as well... I have begun initial work. I just have so little time, but it at top of priority for my software (however, personal matters in my life is taking higher priority than my software so this is no promise... but I will try see if I can somewhere. I have a ton of things I need to get working before I can replace the old webview)

 

TinyPortal © 2005-2018