Bug 56832 - On UWP (and probably WinRT) the JavaScript alert method does nothing when executed in a WebView
Summary: On UWP (and probably WinRT) the JavaScript alert method does nothing when exe...
Status: RESOLVED NOT_ON_ROADMAP
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.3.3
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-05-25 10:59 UTC by John Hardman
Modified: 2017-11-06 22:20 UTC (History)
4 users (show)

Tags: UWP WinRT WebView alert JavaScript ac
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NOT_ON_ROADMAP

Description John Hardman 2017-05-25 10:59:46 UTC
On UWP (and I suspect WinRT as well, although I haven't checked that), calling the JavaScript alert method inside a WebView does not result in the expected alert box being displayed (it is displayed on Android and UWP). It appears that the Xamarin.Forms WebView renderer for UWP does not handle ScriptNotify. Microsoft document that this is necessary at https://code.msdn.microsoft.com/windowsapps/How-to-intercept-854d33da

The UWP WebView renderer needs modifying to handle ScriptNotify.

In the meantime, I have implemented a custom renderer in my app to workaround this. As this shows what needs to be done in the Xamarin.Forms WebView renderer, I have copied my custom renderer source below.


using System;

using Windows.UI.Core;

using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(WebView), typeof(MyAppUniversalWindows.MyAppWebViewRenderer))]
namespace MyAppUniversalWindows
{
    public class MyAppWebViewRenderer : Xamarin.Forms.Platform.UWP.WebViewRenderer, IDisposable
    {
        Windows.UI.Xaml.Controls.WebView _nativeWebView = null;

        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    if (_nativeWebView != null)
                    {
                        _nativeWebView.ScriptNotify -= Control_ScriptNotify;
                        _nativeWebView = null;
                    }
                }
            }
            catch (Exception ex)
            {
                CommonInfrastructure.InsightsWrapper.SilentlyReportExceptionAsync(ex); // we don't await this one
            }

            base.Dispose(disposing);
        }


        protected override async void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            try
            {
                base.OnElementChanged(e); // call this first to have the base class create the native control(s)

                if (_nativeWebView == null)
                {
                    _nativeWebView = Control;

                    if (_nativeWebView != null)
                    {
                        await _nativeWebView.Dispatcher.RunAsync(
                            CoreDispatcherPriority.Normal,
                            async () => await _nativeWebView.InvokeScriptAsync("eval", new[]
                        {
                            // Based on https://code.msdn.microsoft.com/windowsapps/How-to-intercept-854d33da
                            "window.alert = function (AlertMessage) { window.external.notify(AlertMessage); };"
                        }));

                        _nativeWebView.ScriptNotify += Control_ScriptNotify;
                    }
                }
            }
            catch (Exception ex)
            {
                CommonInfrastructure.InsightsWrapper.SilentlyReportExceptionAsync(ex); // we don't await this one
            }
        }

        private async void Control_ScriptNotify(object sender, Windows.UI.Xaml.Controls.NotifyEventArgs e)
        {
            // This is required to show alerts in JavaScript in a WebView
            // See https://code.msdn.microsoft.com/windowsapps/How-to-intercept-854d33da
            Windows.UI.Popups.MessageDialog dialog = new Windows.UI.Popups.MessageDialog(e.Value);
            await dialog.ShowAsync();
        }

    } // public class MyAppWebViewRenderer : Xamarin.Forms.Platform.UWP.WebViewRenderer, IDisposable

} // namespace MyAppUniversalWindows

// eof
Comment 1 John Hardman 2017-05-25 11:58:53 UTC
That workaround code worked when stepping through in debugger. However, for when not stepping through in debugger, be aware that it will need some synchronisation code added to ensure that the script is injected before continuing.
Comment 2 John Hardman 2017-05-25 17:31:21 UTC
Just noticed a Xamarin article about calling from JavaScript into C#. When the display of alert boxes is resolved, care will need to be taken to not break HybridWebView as described at https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/hybridwebview/
Comment 3 Paul DiPietro [MSFT] 2017-06-04 18:11:57 UTC
Thanks for bringing this to attention. Used one of the basic w3schools pages (https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_alert) to test and the alert in fact doesn't show. Setting to confirmed for now.
Comment 4 Paul DiPietro [MSFT] 2017-06-07 21:20:46 UTC
I'd actually like to comment further on this as I had only done an initial review of observed behavior.

After reviewing the official documentation for WebView[1] under "Use of Alert," the behavior of alerts not displaying is by design. I can only guess that this might be for security purposes, or just because alerts are arguably rather undesirable on the modern/mobile web. The same paragraph states that "You might be able to intercept the information displayed by an Alert and do what you want with it in the host application. Whether this is possible depends on how the page is written and whether you have control of it." Thus, there are potentially no guarantees that it would even do what is expected.

Ultimately, I don't know if there's much value here in adding/"fixing" this as it would likely cause more frustration than it's worth and go against intended design. I think the better option is possibly documenting this behavior on our end.

[1] https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.WebView
Comment 5 John Hardman 2017-06-07 23:25:32 UTC
In Microsoft browsers, it does seem to be by design, but I haven't seen a justification for that yet (I have to admit that I haven't spent long searching).

Whilst alerts may be "undesirable" in a modern/mobile web, they are incredibly useful for debugging.

I've integrated alert support, the ability to call JavaScript from C# and get a return value, and the ability for JavaScript to call out to C#, into my app, using a combination of HybridWebView, Adam Pedley's EvaluateJavascript code etc. It works without problem.

If alert is not going to be added by WebView on UWP (and WinRT). I suggest that when the documentation is updated, that also includes updating HybridWebView to include both its current functionality but also an alert implementation.
Comment 6 jerone 2017-11-06 22:20:55 UTC
The proposed workaround in the official documentation for WebView [1] kinda works for alerts in webpages. It, however, doesn't work for frames & iframes. There is also no solution for JavaScript confirms & prompts. 
All three JavaScript functions are normally blocking, but there appears no solution for that in UWP WebView.

[1] https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.webview#use-of-alert