Stefan van de Laarschot
Stefan van de Laarschot

Reputation: 2163

Xamarin Forms Handle Hyperlinks in Webview Navigating issue

I'm developing n app that has some content pages from our CMS that need to be displayed into a WebView since they have HTML with some hyperlinks in it

I'm controlling the hyperlinks which is working as expected on Android. I'm doing this with the Navigating of the Xamarin.Forms.WebView event

I'm able to use e.Url to send the user to a internal page.

Example:

public class HybridWebView : WebView
{
    public String Code { get; set; }

    public HybridWebView()
    {
        Navigating += HybridWebView_Navigating;
    }
    

    private void HybridWebView_Navigating(object sender, WebNavigatingEventArgs e)
    {
       if(e.Url.EndsWith(".aspx")
       {
          var CMS = new CMSView(e.Code, null);
          Navigation.PushAsync(CMS);
          e.Cancel = true;
       }
    }
}

Note this works well!

The problem is:

when I try this on iOS I got a blank/white WebView. I tried to make a CustomRenderer on iOS but since I subclass the WebView to customize it I can't reach the properties Code for example.

How can I reach the properties in the custom renderer for iOS? I know e.NewElement but ShouldStartLoad expects UIWebView and not my custom HybridWebView.

Does anyone has any tips or ideas how I can reach this?

Thanks in advance

Upvotes: 2

Views: 3278

Answers (2)

therealjohn
therealjohn

Reputation: 2398

If you want to use ShouldStartLoad, you'll need to implement a custom UIWebViewDelegate for the native UIWebView being used. This can get tricky because if you replace the existing delegate with a custom one, you'll lose some of the built-in features that Xamarin.Forms WebView provides. Here is the strategy I use to get the best of both:

[assembly: ExportRenderer (typeof (WebView), typeof (CustomWebViewRenderer))]
public class CustomWebViewRenderer : WebViewRenderer
{
    protected override void OnElementChanged (VisualElementChangedEventArgs e)
    {
        base.OnElementChanged (e);

        if (e.OldElement == null) {

            // Need to capture the existing one so we don't loose functionality 
            // that Xamarin.Forms already has
            var existingDelegate = Delegate;

            // Make sure to pass the existing one to the new one
            Delegate = new MyCustomWebViewDelegate(existingDelegate);
        }
    }
}

public class MyCustomWebViewDelegate : UIWebViewDelegate
{
    readonly UIWebViewDelegate existingDelegate;

    public MyCustomWebViewDelegate(UIWebViewDelegate existing)
    {
        existingDelegate = existing;
    }

    public override bool ShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType)
    {
        // You can customize this instead of returning the existingDelegate method
        return existingDelegate.ShouldStartLoad(webView, request, navigationType);
    }

    public override void LoadFailed (UIWebView webView, NSError error)
    {
        existingDelegate.LoadFailed(webView, error);
    }


    public override void LoadingFinished (UIWebView webView)
    {
        existingDelegate.LoadingFinished(webView);
    }


    public override void LoadStarted (UIWebView webView)
    {
        existingDelegate.LoadStarted(webView);
    }

}

Note* On iOS, WebViewRenderer inherits directly from UIWebView, so you don't have a Control property work with. You are a direct subclass of UIWebView and have access to the properties you would expect. See source here.

You can add custom login to the MyCustomWebViewDelegate.ShouldStartLoad method.

Upvotes: 2

jgoldberger - MSFT
jgoldberger - MSFT

Reputation: 6098

In your customer renderer (a subclass of WebViewRenderer I assume) you can cast e.newElement to your HybridWebView type, e.g.:

HybridWebView wv = e.NewElement as HybridWebView;

Then you should be able to access your Code property with wv.Code.

Also the NativeView property of the WebViewRenderer will give you the iOS native UIView to work with. You should be able to cast this to a UIWebView without issue. E.g:

UIWebView nativeUIWebView = NativeView as UIWebView;

I hope this helps!

Upvotes: 4

Related Questions