Lorenzo
Lorenzo

Reputation: 93

Xamarin Android WebView don't fire navigating if "target=_blank"

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;
    }

Upvotes: 2

Views: 2863

Answers (3)

Tim Gerhard
Tim Gerhard

Reputation: 3607

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;
        }
    }

Upvotes: 2

duindain
duindain

Reputation: 545

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

Upvotes: 2

Lorenzo
Lorenzo

Reputation: 93

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;
    }

Upvotes: 5

Related Questions