2

I'm using a webview in xamarin, i followed many tutorials to handle navigation, and all works fine. My issue is : when an anchor tag has a target="_blank" the event Navigating is never fired.

I see arround someone give a javascript solution which remove target=_blank and attach it at the end of href link.

Is really that the right way to do that? Look wired..

Thank you

This is initialization in xamarin.android renderer

        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
    {
        base.OnElementChanged(e);
        global::Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
        if (e.OldElement != null)
        {
            Control.RemoveJavascriptInterface("jsBridge");
            ((HybridWebView)Element).Cleanup();
        }            
        if (e.NewElement != null)
        {
            Control.Settings.JavaScriptEnabled = true;
            Control.Settings.DomStorageEnabled = true;
            Control.Settings.JavaScriptCanOpenWindowsAutomatically = true;
            Control.Settings.SetSupportMultipleWindows(true);
            Control.Settings.AllowFileAccessFromFileURLs = true;
            Control.Settings.AllowUniversalAccessFromFileURLs = true;
            Control.Settings.UserAgentString = Control.Settings.UserAgentString  + " crmvw";                
            Android.Webkit.WebChromeClient xCC = new CustChromeWebViewClient(_context);
            Control.SetWebChromeClient(xCC);
            Control.SetWebViewClient(new CrmWebViewClient(this, $"javascript: {JavascriptFunction}"));     
            Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");     
            Control.LoadUrl(((HybridWebView)Element).Uri);
        }
    }

And this is my navigating event, never fired when anchor has target=_blank

        private void webv_Navigating(object sender, WebNavigatingEventArgs e)
    {
        if (IsFirstLoad) { 
            IsBusy = true;
            IsFirstLoad = false;
        }

        if (e.Url.ToLower().StartsWith("tel:") || e.Url.ToString().StartsWith("wtai:") || e.Url.ToLower().StartsWith("sms:") || e.Url.ToLower().StartsWith("mailto:"))
        {
            e.Cancel = true;
        }
    }

here my override function for URL in my custom WEBView

        public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, Android.Webkit.IWebResourceRequest request)
    {
        Android.Net.Uri url = request.Url;            
        if (url.ToString().StartsWith("tel:") || url.ToString().StartsWith("wtai:"))
        {
            Xamarin.Essentials.PhoneDialer.Open(UtilityXam.Contact.GetPhoneFromHTML(url.ToString()));
            return true;
        }else if (url.ToString().StartsWith("mailto:"))
        {
            UtilityXam.Contact xE = new UtilityXam.Contact();
            string xEmail = UtilityXam.Contact.GetEmailFromHTML( url.ToString());
            var xTask = xE.SendEmail("","",new System.Collections.Generic.List<string>(){ xEmail });
            return true;
        }
        else if (url.ToString().StartsWith("sms:"))
        {
            UtilityXam.Contact xE = new UtilityXam.Contact();
            string xPh = UtilityXam.Contact.GetPhoneFromHTML(url.ToString());
            var xTask = xE.SendSMS("", "", new System.Collections.Generic.List<string>() { xPh });
        }
        else
        {
            view.LoadUrl(url.ToString());
        }
        view.SetDownloadListener(new CrmDownloadListener(_context));
        return true;
    }
Lorenzo
  • 93
  • 10
  • Does this [solution](https://forums.xamarin.com/discussion/101573/open-webview-links-in-external-browser-if-target-is-set-to-blank) answers your question. Detect the url and check if there is target=blank. – nevermore Nov 02 '20 at 06:38
  • I already found and i already try this solution, and it didn't works for me. I add in navigated event the JS function and evaluate it by webview. The event navigating is not fired when i click on target _blank anchor. My question is, why, the event is not fired? – Lorenzo Nov 02 '20 at 14:38
  • Are you using Xamarin.forms or Xamarin.Android? – nevermore Nov 03 '20 at 02:38
  • Does the event fired when click other urls instead of target _blank anchor. – nevermore Nov 03 '20 at 02:41
  • Yes the other URL non target _blank is fired, and the navigating event is in Xamarin.Forms. I also have a renderer in Xamarin.Android, and i init the webview in Element changed event, i enable support for multiple windows , i also add a custom chromeclient and a custom webview in order to add javascript function to invoke c#. – Lorenzo Nov 03 '20 at 08:32
  • In your custom CrmWebViewClient, can you have a try to overload ShouldOverrideUrlLoading or OnLoadResource method to check if these methods fires when open a url with target _blank. – nevermore Nov 03 '20 at 08:50
  • ShouldOverrideUrlLoading is not fired on achor with target =_blank. i dont know if this can help, but this JS code rise all events normally: window.open('https://www.mysite.it', '_blank'); – Lorenzo Nov 03 '20 at 16:09
  • So can you use this JS code to solve your problem? – nevermore Nov 04 '20 at 09:49
  • yes i can try change all the link in my site because is in ASP.NET, this is why i change the agent header when it run in my webview. But i dont like this solution, and i want understand why the anchor link dont work with target=_blank. – Lorenzo Nov 04 '20 at 10:45
  • Can you please have a try with the solution [here](https://stackoverflow.com/questions/27009995/android-webview-links-to-same-window-with-target-blank-to-open-new-window)? It's a native answer and I can help you to translate it to c# if you need. BTW, [here](https://stackoverflow.com/questions/25713069/why-is-wkwebview-not-opening-links-with-target-blank/25853806#25853806) is also a iOS related thread. – nevermore Nov 05 '20 at 09:17
  • <3 thank you! in this way it works. My mistake was exactly not manage the new window event. I really appreciate your patience and your support – Lorenzo Nov 05 '20 at 14:14

3 Answers3

5

After the great help of Jack Hua i'm able to solve the problem. In OnElementChanged of Hybrid renderer i set support for multiple windows.

Control.Settings.SetSupportMultipleWindows(true);

and next i had to menage onCreateWindow event in the custom chrome webview. Here the code converted in c# from the link suggested by Jack.

        public override bool OnCreateWindow(Android.Webkit.WebView view, bool isDialog, bool isUserGesture, Android.OS.Message resultMsg)
    {
        Android.Webkit.WebView newWebView = new Android.Webkit.WebView(_context);
        view.AddView(newWebView);
        Android.Webkit.WebView.WebViewTransport transport = (Android.Webkit.WebView.WebViewTransport) resultMsg.Obj;
        transport.WebView = newWebView;
        resultMsg.SendToTarget();
        return true;
    }
Lorenzo
  • 93
  • 10
  • Can you please accept this answer later (click the ☑️ in the upper left corner of this answer ) so that we can help more people with same problem:). – nevermore Nov 06 '20 at 05:28
  • This opens the new window in chrome and not in the in app browser – Tim Gerhard Aug 12 '21 at 12:25
  • Do I need to create a `HybridWebView` for implementing this solution? – Costas Mar 10 '22 at 17:21
  • I'm trying this solution. In my custom `WebView` code I try to do the `OnCreatedWindow` override, but I get the following error: `CS0115 'HybridWebViewRenderer.OnCreateWindow(WebView, bool, bool, Message)': no suitable method found to override`. Any idea how it can get solved? – Costas Mar 11 '22 at 14:33
2

This is an introduced bug in Xamarin Forms since v4.8.0.1364 (According to the bug report at least)

You can work around it for now by removing the target="_blank" from the url or by setting a property

webView.Settings.SetSupportMultipleWindows(true);

I have fixed it for our app by striping target="_blank" and target='_blank' in some replacement logic that already runs over the content

There are multiple open issues reporting it for Xamarin Forms github

[Bug] Cannot open URLs with WebView android when the target is _blank #12917

[Bug] Android WebView's Navigating and Navigated events not fired #12852

duindain
  • 525
  • 3
  • 12
  • 2
    Those links to the GitHub issue were invaluable; instead of `SetSupportMultipleWindows(true)`, setting it to **false** made all of the `target="_blank"` links start firing through my `Navigating` event – Richard Ockerby Jun 24 '21 at 21:19
2

I tried a completely different approach, because the above answers didn't really help (my target _blank links would always open in a new chrome instance and not in the in-app browser).

First, you'll need to set SetSupportMultipleWindows to false. As soon as you do that, all the windows will open in the same webView:

Control.Settings.SetSupportMultipleWindows(false);

More information on how you set these settings: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview

Next, all I did was change the back-button behaviour, to make sure the back button doesn't close the app and instead navigates the webview pages (HybridWebView is my custom webview that I created in the first step).

    HybridWebView _browser;
    public MainPage()
    {
        _browser = new HybridWebView
        {
            Source = "https://brandschutzplaner-stahltragwerke.promat.ch"
        };

        Content = _browser;
    }

    protected override bool OnBackButtonPressed()
    {

        base.OnBackButtonPressed();

        if (_browser.CanGoBack)
        {
            _browser.GoBack();
            return true;
        }
        else
        {
            base.OnBackButtonPressed();
            return true;
        }
    }
Tim Gerhard
  • 3,477
  • 2
  • 19
  • 40