首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Xamarin HybridWebView抛出EvaluateJavaScript异常

Xamarin HybridWebView抛出EvaluateJavaScript异常
EN

Stack Overflow用户
提问于 2020-06-19 08:00:09
回答 1查看 199关注 0票数 0

昨天我花了几个小时找出为什么我无法访问我的混合wkWebView的(显然是起作用的)参数。在正确启动的iOS覆盖下的DidFinishNavigation部件中,当尝试EvaluateJavaScriptAsync甚至访问NullObjectReference参数时,我总是会得到一个NullObjectReference异常。

然后,我终于发现我看错了对象:我访问的是Forms HybridWebView对象(在“chain”中向上),而不是iOS webview对象(从呈现器向下)。在下面的代码中,"webView“参数来自DidFinishNavingation,而不是webViewRenderer.Element中的_wkWebView (参见最后的代码部分)

现在,我的代码正在工作,但我仍然想知道,我对平台特定集成的总体概念是否正确,还是表单混合视图(如EvaluateJavaScript)中可用的表单函数应该直接工作?我是不是遗漏了一些链接来连接那些与底层iOS网页的链接?

我的HybidWebView共享表单代码:

代码语言:javascript
复制
public class MyWebView : WebView
{
    public event EventHandler SwipeLeft;
    public event EventHandler SwipeRight;

    public void OnSwipeLeft() =>
        SwipeLeft?.Invoke(this, null);

    public void OnSwipeRight() =>
        SwipeRight?.Invoke(this, null);

    public static readonly BindableProperty UrlProperty = BindableProperty.Create(
        propertyName: "Url",
        returnType: typeof(string),
        declaringType: typeof(MyWebView),
        defaultValue: default(string));

    public string Url
    {
        get { return (string)GetValue(UrlProperty); }
        set
        {
            SetValue(UrlProperty, value);
            NotifyPropertyChanged(nameof(HTML));
        }
    }

    public static readonly BindableProperty HTMLProperty = BindableProperty.Create(
        propertyName: "HTML",
        returnType: typeof(string),
        declaringType: typeof(MyWebView),
        defaultValue: default(string));

    public string HTML
    {
        get { return (string)GetValue(HTMLProperty); }
        set
        {
            SetValue(HTMLProperty, value);
            NotifyPropertyChanged(nameof(HTML));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

以及渲染器的连接iOS部件:

代码语言:javascript
复制
    public class MyWebViewRenderer : ViewRenderer<MyWebView, WKWebView>
{
    WKWebView _wkWebView;

    protected override void OnElementChanged(ElementChangedEventArgs<MyWebView> e)
    {
        System.Console.WriteLine("--- Loading wkWebView ---");
        base.OnElementChanged(e);

        if (Control == null)
        {
            Console.WriteLine("+++ WKW: Control null -> init");

            var config = new WKWebViewConfiguration();
            _wkWebView = new WKWebView(Frame, config);

            SetNativeControl(_wkWebView);
            _wkWebView.NavigationDelegate = new ExtendedWKWebViewDelegate(this);

        }

        if (e.NewElement != null)
        {
            Console.WriteLine("+++ WKW: Control exists -> init GestureRecognizers");

            UISwipeGestureRecognizer leftgestureRecognizer = new UISwipeGestureRecognizer(this, new Selector("SwipeEvent:"));

            leftgestureRecognizer.Direction = UISwipeGestureRecognizerDirection.Left;

            UISwipeGestureRecognizer rightgestureRecognizer = new UISwipeGestureRecognizer(this, new Selector("SwipeEvent:"));
            rightgestureRecognizer.Direction = UISwipeGestureRecognizerDirection.Right;

            leftgestureRecognizer.Delegate = new MyWebViewDelegate();
            rightgestureRecognizer.Delegate = new MyWebViewDelegate();

            this.AddGestureRecognizer(leftgestureRecognizer);
            this.AddGestureRecognizer(rightgestureRecognizer);
        }

        NSUrl baseURL = new NSUrl(App.dirNews, true);
        string viewFile = Path.Combine(App.dirNews, "view.html");
        NSUrl fileURL = new NSUrl(viewFile, false);

        if (Element?.HTML != null && Element?.HTML != "")
        {
            System.Console.WriteLine("--- Showing HTTP content ---");
            File.WriteAllText(viewFile, Element.HTML, System.Text.Encoding.UTF8);
            Control.LoadFileUrl(fileURL, baseURL);
        }
        else if (Element?.Url != null && Element?.Url != "")
        {
            System.Console.WriteLine("--- Loading Web page ---");
            System.Console.WriteLine("--- " + Element.Url + " ---");
            NSUrlRequest myRequest = new NSUrlRequest(new NSUrl(Element.Url), NSUrlRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData, 120);
            Control.LoadRequest(myRequest);
        }

    }

最后,DidFinishLoading类中的iOS事件处理程序:

代码语言:javascript
复制
    class ExtendedWKWebViewDelegate : WKNavigationDelegate
{

    MyWebViewRenderer webViewRenderer;

    public ExtendedWKWebViewDelegate(MyWebViewRenderer _webViewRenderer = null)
    {
        webViewRenderer = _webViewRenderer ?? new MyWebViewRenderer();
    }

    [Export("webView:didFinishNavigation:")]
    public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
    {
        try
        {
            var _webView = webViewRenderer.Element as WebView;
            if (_webView != null)
            {
                await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
                _webView.HeightRequest = (double)webView.ScrollView.ContentSize.Height;

                //### get html from site
                var myRes = await webView.EvaluateJavaScriptAsync("document.body.innerHTML");

                //### Flag complete status
                MessagingCenter.Send<object, string>(this, "didFinishNavigation", myRes.ToString());

            }
        }

        catch (Exception ex)
        {
            //Log the Exception
            Console.WriteLine("*** CustomWebView Exception: " + ex.Message + "/" + ex.InnerException);
        }


    }

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-19 12:16:26

当我们调用行时

代码语言:javascript
复制
SetNativeControl(_wkWebView);

您在窗体中定义的WebView再次初始化。因此,您需要在自定义渲染器中实现大部分功能。特别是在WebView of iOS中,如果您想要添加侦听器的生命周期或调用某些JS方法,那么在自定义渲染器中实现它是最好的方法(或者说是唯一的方法)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62465839

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档