Federico Navarrete
Federico Navarrete

Reputation: 3274

Why cannot I open links in an external browser in a WebView (UWP)?

I'm developing a Web App application that is almost finished, the app has a local WebApp that has some links and I'd like to open them in an external browser (Edge, Chrome, etc.).

My code is split in 3 parts:

1) Windows Runtime Component:

using System;
using System.Collections.Generic;
using Windows.Foundation.Metadata;
using Windows.Storage;
using Windows.System;

namespace CallJSInterface
{
    [AllowForWeb]
    public sealed class CallJSCSharp
    {
        public async void OpenURL(string url)
        {
            await Launcher.LaunchUriAsync(new Uri(url));
        }
    }
}

2) WebView code:

XAML:

<WebView x:Name="webView1" Source="ms-appx-web:///Assets/index.html" NavigationStarting="webView1_NavigationStarting" />

C#:

private void webView1_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
    sender.AddWebAllowedObject("CallJSCSharp", pObject: new CallJSCSharp());
}

3) JavaScript (jQuery):

$("a").click(function (event) {
    event.preventDefault();
    CallJSCSharp.OpenURL($(this).attr('href'));
});

But nothing happens, no error, no message, nothing. Does anyone know what should I change? Thanks for your help.

Additional Information: Windows Versions

I'm using the same configuration for both projects.

Upvotes: 2

Views: 1104

Answers (1)

Martin Zikmund
Martin Zikmund

Reputation: 39082

There are two issues that cause the code not to work.

First - the Windows Runtime Component automatically modifies the naming conventions to match the target platform on which it is executed. Because JavaScript method names by convention start with a lowercase letter, you must call the OpenURL method like this:

CallJSCSharp.openURL($(this).attr('href'));

Now you should be able to set a breakpoint in the Windows Runtime Component and see the method is actually called. But there is another catch - the OpenURL method is not called on the UI thread which is required for Launcher to work properly. To circumvent this you need to use Dispatcher:

[AllowForWeb]
public sealed class CallJSCSharp
{
    public async void OpenURL(string url)
    {
        await CoreApplication.MainView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            async () => { 
                 await Launcher.LaunchUriAsync(new Uri(url)); 
            });
    }
}

With this change in place, the code should work as intended.

Finally - thank you for a perfectly written question :-) .

Upvotes: 4

Related Questions