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 !
Xamarin Webview link is opening twice in Android
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;
}
}
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
1 additional answer
Sort by: Most helpful
-
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.