Xamarin HybridWebView从C#调用JS函数

时间:2019-05-09 11:20:19

标签: c# xamarin xamarin.forms xamarin.android android-webview

我正在尝试获得一个HybridWebView,JS和C#代码可以在此相互通信。我遵循了the official docs,可以从JS调用C#代码。但是我也需要另一种方法,在所提到的教程中未对此进行介绍。 这就是我走的距离:

在我的HybridWebView控件中,添加了以下几行:

public event EventHandler CallJavascript;

public void InvokeJS()
{
    if(CallJavascript != null)
    {
        CallJavascript(this, EventArgs.Empty);
    }
}

在我的自定义渲染器中,我在OnElementChanged()方法中添加了CallJavascript方法和它

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

        if (Control == null)
        {
            var webView = new Android.Webkit.WebView(_context);
            webView.Settings.JavaScriptEnabled = true;
            webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
            SetNativeControl(webView);


        }
        if (e.OldElement != null)
        {
            Control.RemoveJavascriptInterface("jsBridge");
            var hybridWebView = e.OldElement as HybridWebView;
            hybridWebView.Cleanup();

            e.OldElement.CallJavascript += OnElementCallJavascript;
        }
        if (e.NewElement != null)
        {
            Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
            Control.LoadUrl($"file:///android_asset/Content/{Element.Uri}");
            e.NewElement.CallJavascript += OnElementCallJavascript;
        }
    }


private void OnElementCallJavascript(object sender, EventArgs e)
{
    var webView = new Android.Webkit.WebView(_context);
    Device.BeginInvokeOnMainThread(() =>
    {
        webView.EvaluateJavascript("javascript:increaseCount();", null);
    });
}

但是,我在OnElementCallJavascript中获取的Webview不是我从中调用方法的WebView,因此不会评估任何javascript。有人知道我如何实现这一目标吗?

3 个答案:

答案 0 :(得分:0)

问题是我正在创建一个新的Android.WebKit.WebView。 像这样使用它可以解决问题:

Device.BeginInvokeOnMainThread(() =>
{
     Control.EvaluateJavascript("javascript:increaseCount();", null);
});

答案 1 :(得分:0)

直接/直接使用类似的方法怎么样?

e.NewElement.CallJavascript  += (sender, args) =>
{                    
    Control.EvaluateJavascript("javascript:increaseCount();", null);
};

答案 2 :(得分:0)

在Xamarin中的HybridWebView中,表单定义了可绑定的布局和操作:

 public class HybridWebView : WebView
{
    Action<string> action;
    public static BindableProperty EvaluateJavascriptProperty =
    BindableProperty.Create(nameof(EvaluateJavascript), typeof(Func<string, Task<string>>), typeof(HybridWebView), null, BindingMode.OneWayToSource);

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

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

    public void Cleanup()
    {
        action = null;
    }

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

在页面中调用EvaluateJavacript:

await webview.EvaluateJavascript("javascript:increaseCount();");

在渲染器中:

private HybridWebView xfWebView;
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
    {
        base.OnElementChanged(e);

        if (Control == null)
        {
            var webView = new Android.Webkit.WebView(_context);
            webView.Settings.JavaScriptEnabled = true;
            webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
            SetNativeControl(webView);


        }
        if (e.OldElement != null)
        {
            Control.RemoveJavascriptInterface("jsBridge");
            var hybridWebView = e.OldElement as HybridWebView;
            hybridWebView.Cleanup();

            e.OldElement.CallJavascript += OnElementCallJavascript;
        }
        if (e.NewElement != null)
        {
            xfWebView = e.NewElement;
            Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
            if (xfWebView != null)
                {
                    xfWebView.EvaluateJavascript = async (js) =>
                    {
                        var reset = new ManualResetEvent(false);
                        var response = string.Empty;
                        Device.BeginInvokeOnMainThread(() =>
                        {
                            Control?.EvaluateJavascript(js, new JavascriptCallback((r) => { response = r; reset.Set(); }));
                        });
                        await Task.Run(() => { reset.WaitOne(); });
                        return response;
                    };
                }
         Control.LoadUrl($"file:///android_asset/Content/{Element.Uri}");
        }
}