SKLn-Rad / Xam.Plugin.Webview

Xamarin Plugin for a HybridWebView in PCL projects.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Collection was Modified crash in didFinishNavigation (iOS)

nlapham opened this issue · comments

Hi,

My production app's top crash is caused by the foreach looping in Xam.Plugin.WebView.iOS -> FormsNavigationDelegate.cs the DidFinishNavigation. There are callbacks we add when the page is finished loading (it has to be once its finished) and this race condition of adding and looping over the callbacks causes intermittent crashing. I forked the repo and made the change for our app, but realized I do not have permissions to make a PR for this repo.

Please update the delegate to the following, or provide insight if you disagree.

The real change is making a copy of the callback dictionaries before looping (.ToList())

        [Export("webView:didFinishNavigation:")]
        public async override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
        {
			if (Reference == null || !Reference.TryGetTarget(out FormsWebViewRenderer renderer)) return;
			if (renderer.Element == null) return;

            renderer.Element.HandleNavigationCompleted(webView.Url.ToString());
            await renderer.OnJavascriptInjectionRequest(FormsWebView.InjectedFunction);

            if (renderer.Element.EnableGlobalCallbacks)
            {
                var globalCallbacks = FormsWebView.GlobalRegisteredCallbacks.ToList();
                foreach (var function in globalCallbacks)
                {
                    await renderer.OnJavascriptInjectionRequest(FormsWebView.GenerateFunctionScript(function.Key));
                }
            }

            var localCallbacks = renderer.Element.LocalRegisteredCallbacks.ToList();
            foreach (var function in localCallbacks)
            {
                await renderer.OnJavascriptInjectionRequest(FormsWebView.GenerateFunctionScript(function.Key));
            }

            renderer.Element.CanGoBack = webView.CanGoBack;
            renderer.Element.CanGoForward = webView.CanGoForward;
            renderer.Element.Navigating = false;
            renderer.Element.HandleContentLoaded();
        }