WebView/UrlWebViewSource and Javascript

JHossJHoss USMember

I am attempting to use the Forms to create a generic html frontend/C# backend application. Basically had it "working" for Android (forget about all the speed issues with the native webview... it is just unusable) right before Xamarin 3 came out. I do think it is awesome! But, how can I create a JavascriptInterface or equivalent as well as javascript injection using the Xamarin.Forms.WebView/Xamarin.Forms.UrlWebViewSource? Looking at the API, I am not seeing anything for those classes that contain that ability (or even an evaluate javascript routine).

Only other approach I can see (and possibly help with the speed issues) is to use Cordova package (http://szymonrozga.net/blog/2013/02/cordova-plugins-in-monodroid/).

Posts

  • JamesMontemagnoJamesMontemagno Xamurai USForum Administrator, Xamarin Team, Developer Group Leader Xamurai
    edited May 2014

    It seems like you might want to look at our Hybrid solution with Razor templates:

    http://blog.xamarin.com/sharper-html-hybrid-apps-with-razor/

    and

    http://blog.xamarin.com/build-hybrid-apps-with-our-new-starter-kit/

    Of course you can mix and match both Xamarin.Forms and razor stuff as well.

  • JHossJHoss USMember

    Cool, I can check that out! Thanks for the feedback

  • TheRealJasonSmithTheRealJasonSmith Xamurai USXamarin Team Xamurai

    The dev team would like to apologize for the extremely simple state of the current webview. It's on our list.

  • JHossJHoss USMember

    Great to know. Would be AWESOME if the webview would actually be chromium or geckofx to support webgl. Probably way beyond scope but had to ask :)

  • TheRealJasonSmithTheRealJasonSmith Xamurai USXamarin Team Xamurai

    Yeah sorry I am pretty sure that wont happen, but I wont say never. It's just so far outside what we would normally target. What I can say there is absolutely nothing stopping someone else from implementing that and making a nuget packages. The API's we use to make Xamarin.Forms are completely available to you as well. It's all just vanilla code, no compiler ju-ju magic, no mystical reflection magic (except where you know... thats expected) just normal, apple pie code.

  • ChrisMuenchChrisMuench USMember

    I had to pause me project because I need three simple things from the WebView:
    the event: OnDocumentLoaded (Supported by all three platforms)
    the method: EvaluateJavaScript (also supported by all three platforms but has different method-name)
    webView.Settings: On Windows Phone JavaScript is turned off by default. On Android the Zoom is off by default etc. I need control over these settings to have same experience (of my HTML5 Browser App) on all three platforms

    Lastly it would be great if we had a common implementation for the event-sink on "Window.external()". Every platform does that differently and its a nightmare to setup.

    Great work so far on the Forms! I love where this is going!

    Cheers
    Chris Muench
    C-Labs. LLC
    http://www.Home-Relay.com

  • TheRealJasonSmithTheRealJasonSmith Xamurai USXamarin Team Xamurai

    @muenchris‌ I have more or less copied your feedback here into an enhancement bug for the webview. Okay I did copy and paste it...

    Thank you so much for the positive feedback, and I will make sure we have handled all of your needs as best we can for the next feature update.

  • ChrisMuenchChrisMuench USMember

    Thanks! I was trying to you the "Renderer" to do what I need to do but it looks like the "Control" is not exposed in the Renderer, yet.
    I see that some Renderers are derived from "NativeRenderer". And it has a property "Control". If that one would contain the native control consistently across all your "Forms-Controls" I think we (the devs) have all we need to manipulate the native controls on the target platforms.

    Tricky part with the WebView is that all three platforms have different defaults that need to be set for each platform.
    Also the way they handle the JavaScript execution and event handling is different. Therefore its quite important to get access to the native control and your "Renderer" is a GREAT way of doing this.

    Cheers
    Chris Muench - C-Labs. LLC (http://www.Home-Relay.com)

  • MartinBowlingMartinBowling ✭✭ USMember, Insider ✭✭

    @JasonASmith also have a project that would be super simple if these things were exposed any ETA on exposing the native control for us to manipulate or including those routines in the Xamarin.Forms.Webivew?

  • oVanoVan ✭✭ BEUniversity ✭✭
  • HugoLogmans_HugoLogmans_ ✭✭✭ NLMember ✭✭✭

    @muenchris and @MartinBowling, the Webview renderer does not contain a Control, because it IS a webview itself. The EntryRenderer example is confusing, because it is a view holding a control, but a Webview has no container.

    I made a custom renderer for webview, because if you set the background to Color.Transparent, on iOS also Opaque = false needs to be set.

    Also the naming on iOS and Android renderer is confusing...

    This is my iOS code:

        [assembly: ExportRenderer(typeof(TransparentWebview), typeof(TransparentWebviewRenderer))]
        namespace Kinderopvang2014.iOS
        {
            public class TransparentWebviewRenderer : WebViewRenderer
            {
                public TransparentWebviewRenderer() : base()
                {
                    Opaque = false;
                }
            }
    
        }
    
  • ChrisMuenchChrisMuench USMember

    Thanks, looks straight forward but not sure it actually works.
    I see the debugger hitting the function but the result on my emulator does not show.
    Also I added:

    this.LoadFinished+=sinkLoadFinished;

    in order to catch the event when the page has been successfully loaded but the event is never fired.

    At this point I don't know if this is not supported, or a bug:)

    For my app, I need all Events (LoadFinished, LoadError, LoadStarted etc).

    On the Android side, the constructor does not work but the OnModelChanged shows a control if I derive my Renderer from WebRenderer.

    But I cannot set any browser "settings". It looks like they are read-only in the OnModelChanged call.
    When is the best time to set these settings on Android?

    Thanks
    Chris

  • BernieHabermeierBernieHabermeier ✭✭ USUniversity ✭✭

    @JasonASmith any news on the progress regarding exposing events like LoadFinished? I'd like to use that as well... In the meantime, is there anything I can do to work around it?

  • CivisogCivisog USMember

    It seems the HybridWebView implements a OnLoadFinished method and a CallJsFunction method . However I didn't manage to make it work on Android. You might get more luck than me.
    You can find it there : https://github.com/XForms/Xamarin-Forms-Labs
    I suppose the Xamarin.Forms' WebView will be replace by something close to this.

  • CivisogCivisog USMember

    I managed to make the HybridWebView from Xamarin.Forms.Labs work on Android. They fixed some issues and now you can call C# from JavaScript and call JavaScript from C# with it.
    If you need to throw JavaScript from C# when a page finished loading, the LoadFinished method still doesn't work but you can use the OnPageFinished in the WebViewClient defined in their custom renderer.
    In order to call C# from JS, you first need to register a call back in your Xamarin.Forms constructor
    e.g. : this.hybridWebView.RegisterCallback("myC#function", x => function(x));
    And then, in your JS, you need to call your function with : Native("myC#function", args);

    To call JS from C#, you can use CallJsFunction, be carefull that your html has been already loaded.
    You can do all you could do with the native webview, what the custom renderer does is declaring a Android.Webkit.WebView and forcing it as the controler => this.SetNativeControl(webView);

  • Joshua_DJoshua_D ✭✭ USMember ✭✭
    edited October 2014

    @Civisog‌, would you be able to post the whole block of code from the used methods in your explanation? You can encapsulate your code using the " ` " symbol (the one above the Tab key on your keyboard) to get appropriate formatting. Just put one at the beginning and end, then the forum's auto-formatting should take over.
    Also, do you have any idea if this solution may work for iOS?

    //THIS IS AN EXAMPLE

    They can also be split, so if you wanted to add text explaining each code block: (Just be sure to encapsulate each block separately.)

    //THEN I CAN ADD ANOTHER

  • SKallSKall ✭✭✭✭ USMember ✭✭✭✭

    A workaround for Android is to put in a native callback on window load JS function (your HTML page). This should be wrapped in try-catch as it this point at least WP has not injected the native callback yet. I will try to find time to debug the Android side to see if there is a better way to get load finished callback.

  • CivisogCivisog USMember
    edited October 2014

    Thanks for the tip @Joshua_D‌!

    To use the Xamarin.Forms.Labs HybridWebView for Android, first you need to add an HybridWebView to your Xamarin.Forms
    <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Exemple.WebView" xmlns:controls="clr-namespace:Xamarin.Forms.Labs.Controls;assembly=Xamarin.Forms.Labs"> <controls:HybridWebView x:Name="hybridWebView" /> </ContentPage>
    Then in the code behind, if you want to call C# from javascript, you need to add a Callback in the constructor of your Xamarin.Forms
    public WebView(string collectionsPath, string manual) { //I don't know if this is needed but I used the hybridWebView constructor where you pass an IJsonSerializer IJsonSerializer jsonSerializer = new SystemJsonSerializer(); hybridWebView = new HybridWebView(jsonSerializer); InitializeComponent (); //adding the callbacks this.hybridWebView.RegisterCallback("callToCSharpMethod", x => CallaMethod(x)); //this is for test this.hybridWebView.RegisterCallback("WriteInConsole", t => System.Diagnostics.Debug.WriteLine(t)); //don't forget to remove the call back when you leave the page //this.hybridWebView.RemoveCallback("callToCSharpMethod"); //this.hybridWebView.RemoveCallback("WriteInConsole"); }
    To load an event when the page is loaded, you can put the code in the OnPageFinished() method from the Client class (WebViewClient) in the file HybridWebViewRenderer.cs of the Xamarin.Forms.Labs.Android project. (There must be better ways to do it but I was just creating a small app for testing).

    In fact I haven't tried to call JavaScript from the Xamarin.Forms code behind. I call some JS from the OnPageFinished() in the renderer.

    To call JS from the Xamarin.Forms I think you should use the InjectJavaScript Method from the HybridWebview (it throws the event JavaScriptLoadRequested which is "binded" to the OnInjectRequest Method from the native renderer).

    I haven't tried it on IOS.

    I talked to @JasonASmith (Xamarin.Forms team) at Evolve 2014 and he told me Xamarin is working on his own HybridWebview right now.

  • Joshua_DJoshua_D ✭✭ USMember ✭✭

    @Civisog‌, thanks! I appreciate you taking the time to post up some code.

  • SKallSKall ✭✭✭✭ USMember ✭✭✭✭

    @Civisog‌, you don't really need to pass the serializer if it is the system serializer. The default behaviour is to assign it based on the content (or lack of) your IOC container. Hiding the dependency this way isn't ideal but it is there to support XAML. The default parameterless constructor is in below link.

    https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/src/Xamarin.Forms.Labs/Xamarin.Forms.Labs/Controls/HybridWebView.cs#L46-L51

    XML comments:

        /// <remarks>HybridWebView will use either <see cref="IJsonSerializer"/> configured
        /// with IoC or if missing it will use <see cref="SystemJsonSerializer"/> by default.</remarks>
    
  • SKallSKall ✭✭✭✭ USMember ✭✭✭✭

    Just FYI, the Android issue (load finished) has now been fixed on the latest code base available from GitHub.

  • PrudveeKrishnaPrudveeKrishna USMember

    @SKall Thank you.

  • mohsenasadimohsenasadi USMember

    Thanks

  • MaheshMudaliyar.7823MaheshMudaliyar.7823 INMember

    How to create a listview with label in it having @mention functionality in it in xamarin forms.

    For Eg: Text on Label:

    Hi this is @username.

    When user will click on @username, an alert with user details should be shown.

Sign In or Register to comment.