Quantcast
Channel: Recent Threads — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 204402

Xamarin.Forms Hybrid Webview

$
0
0

Hi fellas,

I've a HybridWebview with handle JS Event Register and Evaluate JS fuctions and its works well. But i need some improvment on my hybridview whitch is js alert,promp, etc. support. I already find a way in Android side adding setWebCrome parametters. But still have problem with ios part. I find a solution on xamarin recepit called webview handle with js project but i couldn't understand how can i implament this.

Here is my HybridWebview code on X.Forms Side

using System;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace Paperwork.Mobile.CustomControls
{
public class PWHybridWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(
"Uri",
typeof(string),
typeof(PWHybridWebView),
default(string));

    //public static BindableProperty DialogProperty =
    //    BindableProperty.Create(nameof(Dialog), typeof(IUserDialogs), typeof(PWHybridWebView), null);

    //public IUserDialogs Dialog
    //{
    //    get { return (IUserDialogs)GetValue(DialogProperty); }
    //    set { SetValue(UriProperty, value); }
    //}

    public static BindableProperty EvaluateJavascriptProperty =
        BindableProperty.Create(nameof(EvaluateJavascript), typeof(Func<string, Task<string>>),
            typeof(PWHybridWebView), null, BindingMode.OneWayToSource);

    private Action<string> action;

    public Func<string, Task<string>> EvaluateJavascript
    {
        get => (Func<string, Task<string>>) GetValue(EvaluateJavascriptProperty);
        set => SetValue(EvaluateJavascriptProperty, value);
    }

    public string Uri
    {
        get => (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);
    }
}

}


And ios Renderer

using System;
using System.Threading;
using System.Threading.Tasks;
using Foundation;
using Paperwork.Mobile.CustomControls;
using Paperwork.Mobile.iOS.CustomRenderers;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(PWHybridWebView), typeof(PWHybridWebViewRenderer))]

namespace Paperwork.Mobile.iOS.CustomRenderers
{
public class PWHybridWebViewRenderer : ViewRenderer<PWHybridWebView, WKWebView>, IWKScriptMessageHandler,
IWKNavigationDelegate
{
private const string JavaScriptFunction =
"function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";

    private WKUserContentController userController;

    public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
    {
        Element.InvokeAction(message.Body.ToString());
    }

    protected override void OnElementChanged(ElementChangedEventArgs<PWHybridWebView> e)
    {
        base.OnElementChanged(e);

        if (Control == null)
        {
            userController = new WKUserContentController();
            var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd,
                false);
            userController.AddUserScript(script);
            userController.AddScriptMessageHandler(this, "invokeAction");

            var config = new WKWebViewConfiguration {UserContentController = userController};
            var webView = new WKWebView(Frame, config);
            SetNativeControl(webView);
        }

        if (e.OldElement != null)
        {
            userController.RemoveAllUserScripts();
            userController.RemoveScriptMessageHandler("invokeAction");
            var hybridWebView = e.OldElement;
            hybridWebView.Cleanup();
        }

        if (e.NewElement != null)
        {
            Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
            var webView = e.NewElement;
            //webView.EvaluateJavascript.Invoke("Save()");

                webView.EvaluateJavascript = async js =>
                        {
                            var reset = new ManualResetEvent(false);
                            Device.BeginInvokeOnMainThread(async () =>
                            {
                                try
                                {
                                    await Control.EvaluateJavaScriptAsync(js);
                                }
                                catch (Exception exception)
                                {
                                    //
                                }
                            });
                            await Task.Run(() => { reset.WaitOne(); });
                            return null;
                        };

        }
    }
}

}

and also here is a solution from xamarin recepit

using System;

using UIKit;
using WebKit;
using Foundation;
using System.IO;

namespace WKUIDelegateDemo
{
// We'll use the IWKUIDelegate protocol to conform to WKUIDelegate

public partial class ViewController : UIViewController, IWKUIDelegate
{
    WKWebView webView;

    public ViewController (IntPtr handle) : base (handle)
    {
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        // Create a new WKWebView, assign the delegate and add it to the view
        webView = new WKWebView(View.Frame, new WKWebViewConfiguration());
        webView.UIDelegate = this;
        View.AddSubview (webView);

        // Find the Alerts.html file and load it into the WKWebView
        string htmlPath = NSBundle.MainBundle.PathForResource ("Alerts", "html");
        string htmlContents = File.ReadAllText (htmlPath);
        webView.LoadHtmlString (htmlContents, null);
    }

    // Called when a Javascript alert() is called in the WKWebView 
    // The alert panel should display the message and a single "OK" button
    [Foundation.Export ("webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:")]
    public void RunJavaScriptAlertPanel (WebKit.WKWebView webView, string message, WebKit.WKFrameInfo frame, System.Action completionHandler)
    {
        // Create and present a native UIAlertController with the message
        var alertController = UIAlertController.Create (null, message, UIAlertControllerStyle.Alert);
        alertController.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
        PresentViewController (alertController, true, null);

        // Call the completion handler 
        completionHandler ();
    }

    // Called when a Javascript confirm() alert is called in the WKWebView
    // The alert panel should display the message with two buttons - "OK" and "Cancel"
    [Export ("webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:")]
    public void RunJavaScriptConfirmPanel (WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler)
    {
        // Create a native UIAlertController with the message
        var alertController = UIAlertController.Create (null, message, UIAlertControllerStyle.Alert);

        // Add two actions to the alert. Based on the result we call the completion handles and pass either true or false
        alertController.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, okAction => {
            completionHandler(true);
        }));
        alertController.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Default, cancelAction => {
            completionHandler (false);
        }));

        // Present the alert
        PresentViewController (alertController, true, null);
    }

    // Called when a Javascript prompt() alert is called in the WKWebView
    // The alert panel should display the prompt, default placeholder text and two buttons - "OK" and "Cancel"
    [Foundation.Export ("webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:")]
    public void RunJavaScriptTextInputPanel (WebKit.WKWebView webView, string prompt, string defaultText, WebKit.WKFrameInfo frame, System.Action<string> completionHandler)
    {
        // Create a native UIAlertController with the message
        var alertController = UIAlertController.Create (null, prompt, UIAlertControllerStyle.Alert);

        // Add a text field to the alert, set the placeholder text and keep a refernce to the field
        UITextField alertTextField = null;
        alertController.AddTextField ((textField) => {
            textField.Placeholder = defaultText;
            alertTextField = textField;
        });

        // Pass the text to the completion handler when the "OK" button is tapped
        alertController.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, okAction => {
            completionHandler (alertTextField.Text);
        }));

        // If "Cancel" is tapped, we can just return null
        alertController.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Default, cancelAction => {
            completionHandler (null);
        }));

        // Present the alert
        PresentViewController (alertController, true, null);
    }
}

}


Viewing all articles
Browse latest Browse all 204402

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>