How does one implement WkWebView (iOS) in a cross-platform application?

I have a cross-platform mobile app (Android/iOS) which implements the generic WebView control. This works well for most circumstances, but some iOS users complain that, when attempting to load a certain resource-intensive web page, the app "goes black" and then focus returns to the Menu view. My suspicion is that the app is choking due to the amount of content and processing overhead of the web page, but frankly this is a blind guess and I don't have the resources (such as an iPhone at my disposal) in order to verify this. Using an iPhone simulator on a Mac does not reproduce the "black screen" issue.

Therefore, I am attempting to implement in parallel WkWebView for iOS devices at version 8.0 and above as this is presumably more performant and might alleviate the problem. It is just about working, but there seems to be a disconnect between the ViewController and ContentPage which is supposed to host the WkWebView control which I have been unable to rectify.

Below is the general implementation:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class WkWebViewPage : ContentPage
{
    public WkWebViewPage (string url, string title)
    {
        InitializeComponent();

        Title = title;

        App.GetWkWebView(this, url);
    }
}

The markup for WkWebPageView has no inner content.

The method App.GetWkWebView is a delegate of type Action<Page, string> implemented as a static property in the main App class. This is assigned in the FinishedLaunching method of the AppDelegate class (iOS project) to a static method in the static class I am using to manage invoking the WkWebView. This class is implemented as such:

public static class WkWebViewController
{
    private static WKWebView _wkWebView;

    public static void GetWkWebView(Page parentView, string url)
    {
        if(_wkWebView == null)
        {

    // INSERT ATTEMPTED APPROACHES BELOW HERE

            var frame = view.Frame;

            var cgRect = new CoreGraphics.CGRect(frame.X, frame.Y, frame.Width, frame.Height);

            _wkWebView = new WKWebView(cgRect, new WKWebViewConfiguration());

            view.AddSubview(_wkWebView);

    // NavigationDelegate is a custom class; not germane to the issue
            _wkWebView.NavigationDelegate = new NavigationDelegate();
        }

        var nsUrl = new NSUrl(url);
        var request = new NSUrlRequest(nsUrl);

        _wkWebView.LoadRequest(request);
    }
}

Here is where the trouble begins. I have tried two approaches to obtaining the appropriate ViewController -- and more pertinently, the UIView object:

1)

            var renderer = Platform.GetRenderer(parentView);

            if (renderer == null)
            {
                renderer = Platform.CreateRenderer(parentView);
                Platform.SetRenderer(parentView, renderer);
            }

            var view = renderer.ViewController.View;

This results in:

I WOULD POST AN IMAGE HERE, BUT AM PREVENTED FROM DOING SO; THEREFORE, PLEASE USE YOUR IMAGINATION.

The content area is white/blank. The http request is submitted successfully as a 200 response is received. Note that the navigation bar above the content area properly displays.

2)

            var window = UIApplication.SharedApplication.KeyWindow;

            var vc = window.RootViewController;

            while (vc.PresentedViewController != null)
            {
                vc = vc.PresentedViewController;
            }

            var view = vc.View;

which results in:

I WOULD POST ANOTHER IMAGE HERE, BUT AM PREVENTED FROM DOING SO; THEREFORE, PLEASE USE YOUR IMAGINATION FOR A SECOND TIME.

In this case, the web page displays; however, the WkWebView control takes up the entire screen, obscuring the navigation bar (and seemingly the Status Bar).

Any suggestions would be greatly appreciated!

NOTE: Links to images for approaches 1 and 2 can be provided upon request.

Best Answer

Answers

  • tmccoidtmccoid USMember

    This is a simple, clear, and elegant solution. Thank you for your help!

  • mshwfmshwf EGMember ✭✭✭
    edited October 2018

    @LandLu Hi, I also need to implement the WKWebView as there are problems in rendering HTML with UIWebView, I don't want to create custom control in the shared project, I want to use the WebView directly and utilize the Source property where it can be an HTML or a URL, also I don't want to break the current code where the WebView is used heavily.
    I tried this:

     public class MyWebViewRenderer : ViewRenderer<WebView, WKWebView>
        {
            WKWebView _wkWebView;
    
            protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    var config = new WKWebViewConfiguration();
                    _wkWebView = new WKWebView(Frame, config);
                    SetNativeControl(_wkWebView);
                }
                if (e.NewElement != null)
                {
                    Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Source)));
                }
            }
        }
    

    but new NSUrl(Element.Source) is not valid!

  • JohannesHJohannesH Member ✭✭
    edited March 5

    @mshwf said:
    @LandLu Hi, I also need to implement the WKWebView as there are problems in rendering HTML with UIWebView, I don't want to create custom control in the shared project, I want to use the WebView directly and utilize the Source property where it can be an HTML or a URL, also I don't want to break the current code where the WebView is used heavily.
    I tried this:

     public class MyWebViewRenderer : ViewRenderer<WebView, WKWebView>
        {
            WKWebView _wkWebView;
    
            protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    var config = new WKWebViewConfiguration();
                    _wkWebView = new WKWebView(Frame, config);
                    SetNativeControl(_wkWebView);
                }
                if (e.NewElement != null)
                {
                    Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Source)));
                }
            }
        }
    

    but new NSUrl(Element.Source) is not valid!

    @mshwf Change "Element.Source" to "(Element.Source as UrlWebViewSource).Url"

Sign In or Register to comment.