Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.
This repository was archived by the owner on May 1, 2024. It is now read-only.

[macOS] NRE in WebViewRenderer #4001

@slakul

Description

@slakul

Description

Removing WebView from a Page causes NullReferenceException.
Stack trace:

Object reference not set to an instance of an object
  at Xamarin.Forms.Platform.MacOS.WebViewRenderer+FormsWebFrameDelegate.FinishedLoad (WebKit.WebView sender, WebKit.WebFrame forFrame) [0x00017] in <51ba4bc9dbf845159a2acda030a83ce4>:0 
  at (wrapper managed-to-native) AppKit.NSApplication.NSApplicationMain(int,string[])
  at AppKit.NSApplication.Main (System.String[] args) [0x00040] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.8.0.22/src/Xamarin.Mac/AppKit/NSApplication.cs:100 
  at LogotecAppStudio.macOS.MainClass.Main (System.String[] args) [0x00017] in /Users/kulikow/Desktop/Projects/AppStudio2018/LogotecAppStudio/LogotecAppStudio.macOS/Main.cs:11

There is a bug in method FinishedLoad. It assumes that _renderer.Control is never null, but it is not true. Below is my workaround.

Steps to Reproduce

  1. Create WebView on a Page
  2. Navigate to any page
  3. Remove the WebView from the page during navigation

Expected Behavior

There should not be any exception.

Actual Behavior

It throws NRE and kills the application.

Basic Information

  • Version with issue: 3.3.0.871608-pre2
  • Last known good version:
  • IDE: Visual Studio for Mac
  • Platform Target Frameworks: Mac

Workaround

using System;
using System.Threading.Tasks;
using Foundation;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.MacOS;
using WebView = Xamarin.Forms.WebView;

[assembly: ExportRenderer(typeof(WebView), typeof(LogotecAppStudio.macOS.Renderers.LasWebViewRenderer))]
namespace LogotecAppStudio.macOS.Renderers
{
	public class LasWebViewRenderer : WebViewRenderer
	{
		protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
		{
			base.OnElementChanged(e);

			if (Control != null &&
				Control.FrameLoadDelegate is FormsWebFrameDelegate == false &&
				Control.FrameLoadDelegate is WebKit.WebFrameLoadDelegate wfd)
			{
				Control.FrameLoadDelegate = new FormsWebFrameDelegate(this, wfd);
			}
		}

		internal class FormsWebFrameDelegate : WebKit.WebFrameLoadDelegate
		{
			WebViewRenderer _renderer;
			WebKit.WebFrameLoadDelegate _wfd;

			internal FormsWebFrameDelegate(WebViewRenderer renderer, WebKit.WebFrameLoadDelegate wfd)
			{
				_renderer = renderer;
				_wfd = wfd;
			}

			public override void FinishedLoad(WebKit.WebView sender, WebFrame forFrame)
			{
				try
				{
					if (_renderer.Control == null) return;
					_wfd.FinishedLoad(sender, forFrame);
				}
				catch
				{
					// ignore
				}
			}

			public override void FailedLoadWithError(WebKit.WebView sender, NSError error, WebFrame forFrame)
			{
				try
				{
					if (_renderer.Control == null) return;
					_wfd.FailedLoadWithError(sender, error, forFrame);
				}
				catch
				{
					// ignore
				}
			}
		}
	}
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions