Вчера я потратил несколько часов, выясняя, почему я не могу получить доступ к (явно работающим) параметрам моего Hybrid wkWebView. В части iOS под правильно запущенным переопределением DidFinishNavigation я всегда получал исключение NullObjectReference при попытке EvaluateJavaScriptAsyn c или даже доступа к параметру Source.
Затем я наконец обнаружил, что смотрю на неправильный объект: я обращался к объекту Forms HybridWebView (вверху в «цепочке») вместо объекта iOS webview (вниз от средства визуализации). В приведенном ниже коде параметр «webView» из DidFinishNavingation заменяет _wkWebView из webViewRenderer.Element (см. Последнюю часть кода)
Теперь мой код работает, но мне все еще интересно, есть ли моя общая концепция специфика платформы c интеграция правильная или функции форм, доступные в формах hybridwebview (например, Evaluate JavaScript), должны работать напрямую? Мне не хватает какой-то ссылки для подключения их к базовому веб-просмотру iOS?
Код моих общих форм для 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);
}
}
и, наконец, обработчик события DidFinishLoading в классе iOS:
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);
}
}
}