Xamarin Webview link is opening twice in Android

gponcec 191 Reputation points
2020-12-18T18:07:42.233+00:00

Hello, I want to open urls in a browser and I found some discussions about:

https://stackoverflow.com/questions/53704452/how-can-i-modify-a-webview-in-xamarin-forms-to-open-links-in-a-browser-on-the-de
https://forums.xamarin.com/discussion/38243/webview-open-external-browser

Then, my solution was to
a) use Browser.OpenAsync to open it the browser
b) use e.Cancel = true to avoid the opening in the webview

Expected: touch link and open the browser.
What happend: touch link, open url in webview and then open url in the browser. If I try to goback it show the webview with the url content.

How can I avoid to open the url first in webview?

Information about my project

  • Visual Studio 2019 Version 16.8.3 on Windows
  • Android target version: 10.0 (Q)
  • Minimum android version: 4.4
  • Xamarin Forms version: 4.6.0.1141
  • Xamarin Essentials version: 1.5.0

The Navigation event in code-behind

        public void OnNavigating(object sender, WebNavigatingEventArgs e)  
        {  
            if (e.Url.StartsWith("http") && !e.Url.Equals(URL))  
            {  
                try  
                {  
                    var uri = new Uri(e.Url);  
                    Browser.OpenAsync(uri);  
                }  
                catch (Exception)  
                {  
                }  
  
                e.Cancel = true;  
            }  
        }  

49592-webview-problem.gif

If it helps to understand o problem, I also implemented and webview renderer for android and its method OnElementChanged. Also, methods OnPageFinished and OnPageStarted were overridden in WebViewClient.

OnElementChanged implementation:

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)  
        {  
            base.OnElementChanged(e);  
            Control.VerticalScrollBarEnabled = false;  
            Control.Settings.JavaScriptEnabled = true;  
            Control.Settings.SetGeolocationEnabled(true);  
            Control.Settings.DomStorageEnabled = true;  
            Control.Settings.SetAppCacheEnabled(true);  
            Control.Settings.JavaScriptCanOpenWindowsAutomatically = true;  
            Control.Settings.SetGeolocationDatabasePath(Control.Context.FilesDir.Path);  
  
            Control.Settings.CacheMode = CacheModes.CacheElseNetwork;  
  
            if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)  
            {  
                Control.SetLayerType(Android.Views.LayerType.Hardware, null);  
            }  
            else  
            {  
                Control.SetLayerType(Android.Views.LayerType.Software, null);  
            }  
  
            Control.SetWebChromeClient(new GeoWebClient());  
  
            if (Control != null)  
            {  
                Control.SetWebViewClient(new WebClient(this));  
            }  
        }  

WebViewClient implementation:

    class WebClient : WebViewClient  
    {  
        GeoWebViewRenderer _renderer;  
  
        public WebClient(GeoWebViewRenderer renderer)  
        {  
            _renderer = renderer ?? throw new ArgumentNullException("renderer");  
        }  
  
        public override void OnPageFinished(Android.Webkit.WebView view, string url)  
        {  
            base.OnPageFinished(view, url);  
  
            var source = new UrlWebViewSource { Url = url };  
            var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);  
            _renderer.ElementController.SendNavigated(args);  
        }  
  
        public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)  
        {  
            base.OnPageStarted(view, url, favicon);  
  
            var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);  
            _renderer.ElementController.SendNavigating(args);  
        }  
    }  
Developer technologies .NET Xamarin
0 comments No comments
{count} votes

Accepted answer
  1. gponcec 191 Reputation points
    2020-12-30T00:38:46.643+00:00

    I tested your proposal and it doesn't work for me. However, I solved my problem by removing the class WebClient and its instance of the OnElementChanged function. I hope this help someone in the future. Thanks a lot @JarvanZhang !

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. JarvanZhang 23,971 Reputation points
    2020-12-21T06:47:18.35+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    The navigating event will be triggered twice when opening a url, you could add a breakpoint to check that. When the event is called for the second time, the Url has been added a '/' at the end. That should the cause.

       private void browser_Navigating(object sender, WebNavigatingEventArgs e)  
       {  
           var str = e.Url;  
       }  
    

    To fix the issue, try adding another condition sentence like below:

       private void browser_Navigating(object sender, WebNavigatingEventArgs e)  
       {  
           if (e.Url.StartsWith("http") && !e.Url.Equals("https://www.google.com") && !e.Url.Equals("https://www.google.com/"))  
           {  
               try  
               {  
                   var uri = new Uri(e.Url);  
                   Browser.OpenAsync(uri);  
               }  
               catch (Exception)  
               {  
               }  
         
               e.Cancel = true;  
           }  
       }  
    

    Best Regards,

    Jarvan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.