Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open a Browser Window with Javascript on Xamarin.Forms #2633

Closed
berkbb opened this issue Feb 10, 2020 · 4 comments
Closed

Open a Browser Window with Javascript on Xamarin.Forms #2633

berkbb opened this issue Feb 10, 2020 · 4 comments

Comments

@berkbb
Copy link

berkbb commented Feb 10, 2020

Hi

I have a Xamarin.Forms app. It includes a button like this:


<Button x:Name="Buy_Button" Text="Satın Al" FontAttributes="Bold" TextColor="#e2e2e2" BackgroundColor="#2A52BE" FontFamily="Segoe UI" Grid.Column="2" Grid.ColumnSpan="1" Grid.RowSpan="1"  CornerRadius="5"  VerticalOptions="Start" HorizontalOptions="Center" FontSize="15.667" Grid.Row="0" Margin="0,10,10,0"  Clicked="Buy_Button_ClickedAsync" CommandParameter="{Binding  Buy_URL}" />`

I'm sending a URL link to click event for opening specific web page. Code is:

  private async void Buy_Button_ClickedAsync(object sender, EventArgs e)
    {
        Button btn = (Button)sender; // Coming button from click event handler.
        var buylink = btn.CommandParameter.ToString(); // Get the CommandParameter.
                                                       //  await DisplayAlert("Satın alma linki", buylink, "Anladım"); // Show the link.
        try // Uwp & iOS & Android
        {
            await Browser.OpenAsync(new Uri(buylink), BrowserLaunchMode.SystemPreferred); // Open url in-app browser for iOS & Android- native in UWP
        }
        catch (NotImplementedInReferenceAssemblyException ex) //Wasm falls here because lack of Xamarin.Essentials.
        {
            // await DisplayAlert("Hata", ex.Message, "Anladım"); // Show the info about exception.

            // Jint - nt is a Javascript interpreter for .NET which provides full ECMA 5.1 compliance and can run on any .NET platform. 
            //Because it doesn't generate any .NET bytecode nor use the DLR it runs relatively small scripts faster. 
            //https://github.com/sebastienros/jint

            var engine = new Engine();
            engine.SetValue("log", new Action<object>(Console.WriteLine));

            engine.Execute(@"function openurl() { log('" + buylink + "'); }; openurl(); ");
        }
    }

In UWP, Xamarin.iOS and Xamarin. Android this code is running via Xamarin.Esssentials:

await Browser.OpenAsync(new Uri(buylink), BrowserLaunchMode.SystemPreferred); 
// Open url in-app browser for iOS & Android- native in UWP

However, my Xamarin.Forms app projected to WebAssembly code with Uno Platform, so this code block not running. As a result. I install Jint to Xamarin.Forms app. This catch block prints the link to Browser console, but no window.open function track in API reference:

catch (NotImplementedInReferenceAssemblyException ex) //Wasm falls here because lack of Xamarin.Essentials.
            {
                // await DisplayAlert("Hata", ex.Message, "Anladım"); // Show the info about exception.

                       // Jint - nt is a Javascript interpreter for .NET which provides full ECMA 5.1 compliance and can run on any .NET platform. 
                //Because it doesn't generate any .NET bytecode nor use the DLR it runs relatively small scripts faster. 
                //https://github.com/sebastienros/jint

                var engine = new Engine();
                engine.SetValue("log", new Action<object>(Console.WriteLine));

                engine.Execute(@"function openurl() { log('" + buylink + "'); }; openurl(); ");
            }
        }

How can I open WebBrowser page on WASM via Javascript form Xamarin.Forms C# code? Thanks.

@carldebilly
Copy link
Member

carldebilly commented Feb 10, 2020

@berkbb: Answered on Stack Overflow...
https://stackoverflow.com/a/60153482/1176099

Stack Overflow
I have a Xamarin.Forms app. It includes a button like this:

<Button x:Name="Buy_Button" Text="Satın Al" FontAttributes="Bold" TextColor="#e2e2e2" BackgroundColor="#2A52BE" FontFamily="Segoe UI...

@jeromelaban jeromelaban added the triage/needs-information Indicates an issue needs more information in order to work on it. label Feb 11, 2020
@berkbb
Copy link
Author

berkbb commented Feb 14, 2020

Hi.

I solved it via Customizing via WebView: Wish that Xamarin.Essentials start works on WASM.

Try to create the webView custom renderer that extends the WebView to
allow C# code to be invoked from JavaScript.

The process for WebView Renderer:

Create the HybridWebView custom control. Consume the HybridWebViewfrom
Xamarin.Forms. Create the custom renderer for the HybridWebView on
each platform. When the user clicks an HTML button, a JavaScript
function will invoke a C# Action.

1.Create the HybridWebView

public class HybridWebView : WebView
{
    Action<string> action;

    public static readonly BindableProperty UriProperty = BindableProperty.Create(
        propertyName: "Uri",
        returnType: typeof(string),
        declaringType: typeof(HybridWebView),
        defaultValue: default(string));

    public string Uri
    {
        get { return (string)GetValue(UriProperty); }
        set { SetValue(UriProperty, value); }
    }

    public void RegisterAction(Action<string> callback)
    {
        action = callback;
    }

    public void Cleanup()
    {
        action = null;
    }

    public void InvokeAction(string data)
    {
        if (action == null || data == null)
        {
            return;
        }
        action.Invoke(data);
    }
}

2.Consume the HybridWebView

<ContentPage
             xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
             x:Class="CustomRenderer.HybridWebViewPage"
             Padding="0,40,0,0">
    <local:HybridWebView x:Name="hybridWebView"
                         Uri="index.html" />
</ContentPage>

3.Create the custom renderer on UWP

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.UWP
{
    public class HybridWebViewRenderer : WebViewRenderer
    {
        const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                Control.NavigationCompleted -= OnWebViewNavigationCompleted;
                Control.ScriptNotify -= OnWebViewScriptNotify;
            }
            if (e.NewElement != null)
            {
                Control.NavigationCompleted += OnWebViewNavigationCompleted;
                Control.ScriptNotify += OnWebViewScriptNotify;
                Control.Source = new Uri($"ms-appx-web:///Content//{((HybridWebView)Element).Uri}");
            }
        }

        async void OnWebViewNavigationCompleted(Windows.UI.Xaml.Controls.WebView sender, WebViewNavigationCompletedEventArgs args)
        {
            if (args.IsSuccess)
            {
                // Inject JS script
                await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction });
            }
        }

        void OnWebViewScriptNotify(object sender, NotifyEventArgs e)
        {
            ((HybridWebView)Element).InvokeAction(e.Value);
        }
    }
}

At the last, call function from code:

hybridWebView.RegisterAction(data => Browser.OpenAsync(data, BrowserLaunchMode.SystemPreferred));
               hybridWebView.InvokeAction("http://localhost");

@no-response no-response bot removed the triage/needs-information Indicates an issue needs more information in order to work on it. label Feb 14, 2020
@joseluisct
Copy link

Hi,

I am using Device.OpenUri and it works in WASM with Xamarin.Forms
Device.OpenUri(new Uri("https://www.bing.com"));

@berkbb
Copy link
Author

berkbb commented Mar 6, 2020

Hi,

I am using Device.OpenUri and it works in WASM with Xamarin.Forms
Device.OpenUri(new Uri("https://www.bing.com"));

Thanks. I will try again :)

@berkbb berkbb closed this as completed May 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants