【问题标题】:Xamarin HybridWebView throwing exception at EvaluateJavaScriptXamarin HybridWebView 在 EvaluateJavaScript 抛出异常
【发布时间】:2020-06-19 08:00:09
【问题描述】:

昨天我花了几个小时找出为什么我无法访问我的 Hybrid wkWebView 的(显然工作的)参数。 在正确触发的 DidFinishNavigation 覆盖下的 iOS 部分中,我在尝试 EvaluateJavaScriptAsync 甚至访问 Source 参数时总是遇到 NullObjectReference 异常。

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

现在我的代码正在运行,但我仍然想知道我对平台特定集成的总体概念是否正确,或者表单 hybridwebview 中可用的表单函数(例如 EvaluateJavaScript)是否应该直接运行?我是否缺少一些链接来将这些链接与底层 iOS webview 连接起来?

我的 HybidWebView 共享表单代码:

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 部分:

    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);
        }

    }

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

    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);
        }


    }

}

【问题讨论】:

  • 既然您的代码运行良好,您现在想做什么?实现一些功能或其他什么?
  • 我的问题是,像 EvaluateJavaScript 这样的 Forms webview 函数是否仍应与自定义 webview 渲染器一起使用,或者,一旦您拥有自定义渲染器,您是否需要自己实现所有内容?通常你会调用“base.xx”来传递重载类的默认实现,但是对于 didFinishNavigation 函数是不允许的。

标签: xamarin wkwebview custom-renderer


【解决方案1】:

当我们调用该行时

SetNativeControl(_wkWebView);

您在 Forms 中定义的WebView 再次被初始化。所以你需要在 Custom Renderer 中实现大部分功能。特别是在iOS的WebView中,如果你想在它的生命周期中添加监听器或者调用一些JS方法,在Custom Renderer中实现是最好的方式(或者唯一的方式)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2016-04-27
    • 2015-09-06
    • 2012-01-24
    • 1970-01-01
    • 2019-04-02
    相关资源
    最近更新 更多