BlazorMobile icon indicating copy to clipboard operation
BlazorMobile copied to clipboard

[Bug] href=javascript:void(0) opens the browser on android

Open arivera12 opened this issue 4 years ago • 18 comments

When there is a link like this <a href="javascript:void(0)">Link</a> The blazor app opens the browser.

I haven't tested ios and windows phone to check if this behavior occurs cause I don't have those device to test them out.

arivera12 avatar Mar 24 '20 04:03 arivera12

Read this documentation :

https://github.com/Daddoon/BlazorMobile#validating-the-blazor-application-navigation

Maybe I will remove the default code I made in template as people always ask without reading.

But I agree, this behavior on JavaScript is surely a side effect with GeckView Navigation event on Android even if it’s not a real full navigation.

Daddoon avatar Mar 24 '20 10:03 Daddoon

@Daddoon

I ended adding this condition and works perfectly.

if (e.Url.StartsWith("javascript:void", StringComparison.OrdinalIgnoreCase))
{
     e.Cancel = true;
}

Why you just don't add this condition on the OnBlazorWebViewNavigating.

I think it's pretty obvious when we add javascript:void or javascript:void(0) on a href we don't want the browser to do anything.

arivera12 avatar Mar 24 '20 18:03 arivera12

Read this documentation :

https://github.com/Daddoon/BlazorMobile#validating-the-blazor-application-navigation

Maybe I will remove the default code I made in template as people always ask without reading.

But I agree, this behavior on JavaScript is surely a side effect with GeckView Navigation event on Android even if it’s not a real full navigation.

I think the default code is ok.

If something its a different from base address of the application it should open the browser.

That behavior is ok for most cases.

But when href is javascript:void it should not do anything.

arivera12 avatar Mar 24 '20 19:03 arivera12

I agree with you.

Maybe i will add some kind of workaround for Android for this case at low level. Actually only this platform may fire this, it doesn't use the same mecanism for forwarding request events, that's why there is a WebExtension loaded on Android (and also why there is a BlazorMobile.Build.Android NuGet package !) .

There is a WebExtension loaded with the GeckoView engine by myself, that listen to onBeforeRequest events and forward them a the BlazorMobile webserver in order to receive the navigation validation logic from Native.

The only problem is as your issue here: It seem that Mozilla WebExtensions has strange (in my opinion) side effects, like javascript void firing this event, or even the javascript history navigation engine (even if the page is not reloaded), there is an issue already opened for this i will try to figure one day.

Maybe there is other edge case i don't know yet.

Daddoon avatar Mar 24 '20 19:03 Daddoon

I am testing hash -> # with href to see if navigates to specific content and doesn't navigate.

I add a href="#test" and element with id="test" and doesn't work.

arivera12 avatar Mar 24 '20 19:03 arivera12

I'm not sure the hash thing work on Blazor generally.

Were you expecting a Navigation event on Android ? As far as i know, this is not always considered as a navigation.

Do you have a different behavior if you test your code from an external browser with remote debugging ?

Daddoon avatar Mar 24 '20 19:03 Daddoon

Yes I am on android.

arivera12 avatar Mar 24 '20 19:03 arivera12

haven't test browser 1 min

arivera12 avatar Mar 24 '20 19:03 arivera12

same behavior on browser doesn't navigate to content.

arivera12 avatar Mar 24 '20 19:03 arivera12

If it doesn't work externally too, it's not related to BlazorMobile but maybe on Blazor generally speaking.

Daddoon avatar Mar 24 '20 19:03 Daddoon

haven't try on blazor. Let me create a blazor fiddle and test it out.

arivera12 avatar Mar 24 '20 19:03 arivera12

I created a fresh simple blazor fiddle to test hash navigation and doesn't work on blazor. Blazor just behaves like that. https://blazorfiddle.com/s/35gc9a26

There should be a work around for that but is ok by your side.

arivera12 avatar Mar 24 '20 20:03 arivera12

I agree with you.

Maybe i will add some kind of workaround for Android for this case at low level. Actually only this platform may fire this, it doesn't use the same mecanism for forwarding request events, that's why there is a WebExtension loaded on Android (and also why there is a BlazorMobile.Build.Android NuGet package !) .

There is a WebExtension loaded with the GeckoView engine by myself, that listen to onBeforeRequest events and forward them a the BlazorMobile webserver in order to receive the navigation validation logic from Native.

The only problem is as your issue here: It seem that Mozilla WebExtensions has strange (in my opinion) side effects, like javascript void firing this event, or even the javascript history navigation engine (even if the page is not reloaded), there is an issue already opened for this i will try to figure one day.

Maybe there is other edge case i don't know yet.

ohh I see but its still very strange behavior. There should be a easy quick fix for this internally on GeckoView engine for other cases. In the meantime my condition worked perfectly.

arivera12 avatar Mar 24 '20 20:03 arivera12

I added an additional condition in the controller managing how requests validation are managed by the end user on Android.

All request starting with javascript: should be ignored (not transfered to the Navigation validator) and considered as a cancelled navigation.

This mean that in the next version shipped, you should not have to manage by yourself anymore javascript: requests, as they will not be forwarded.

Snippet of code in the BlazorController that validate the behavior (just for info):

        private bool ShouldExcludeFromNavigatingEvent(string uri, out bool shouldCancel)
        {
            shouldCancel = false;

            if (!string.IsNullOrEmpty(uri))
            {
                if (uri.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
                {
                    shouldCancel = true;
                    return true;
                }
            }

            return false;
        }

        private async Task<bool> ValidateRequestAndroid(string webextensionId)
        {
            string cancel = "false";

            if (int.TryParse(webextensionId, out int runtimeId))
            {
                var webview = WebViewHelper.GetWebViewByRuntimeIdentity(runtimeId);
                if (webview != null)
                {
                    string uri = this.Request.QueryString.Get("uri");
                    string referrer = this.Request.QueryString.Get("referrer");

                    if (ShouldExcludeFromNavigatingEvent(uri, out bool shouldCancel))
                    {
                        if (shouldCancel)
                        {
                            cancel = "true";
                        }
                    }
                    else
                    {
                        var args = new WebNavigatingEventArgs(
                        WebNavigationEvent.NewPage,
                        new UrlWebViewSource() { Url = referrer },
                        uri);

                        webview.SendNavigating(args);

                        if (args.Cancel)
                        {
                            cancel = "true";
                        }
                    }
                }
            }

            IWebResponse response = new EmbedIOWebResponse(this.Request, this.Response);
            response.SetEncoding("UTF-8");
            response.AddResponseHeader("Cache-Control", "no-cache");
            response.SetStatutCode(200);
            response.SetReasonPhrase("OK");
            response.SetMimeType("text/plain");
            await response.SetDataAsync(new MemoryStream(Encoding.UTF8.GetBytes(cancel)));
            return true;
        }

Daddoon avatar Mar 27 '20 13:03 Daddoon

Nice! keep up the good work! I will have this in consideration,

arivera12 avatar Mar 27 '20 23:03 arivera12

Is this shipped in 3.2.4? Is yes I commented my code and android opens the browser again.

arivera12 avatar Mar 28 '20 00:03 arivera12

Yes it should.

However I didn’t test as it seemed simple. I will check that in the future, it’s not blocking.

Daddoon avatar Mar 28 '20 01:03 Daddoon

I know, it was so simple that didn't need test hahahaha but didn't work at all.

arivera12 avatar Mar 28 '20 02:03 arivera12