From f0d8a9038dfa88d52e120247b385951d373172bd Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 18 Jan 2020 11:59:24 -0700 Subject: [PATCH] Reload the web view every 10 renderings to clean it up. Issue #1487 --- iOS/Article/WebViewController.swift | 107 ++++++++++++++++------------ 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 4722488ab..eee317fa2 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -28,6 +28,7 @@ class WebViewController: UIViewController { private var topShowBarsViewConstraint: NSLayoutConstraint! private var bottomShowBarsViewConstraint: NSLayoutConstraint! + private var renderingTracker = 0 private var webView: WKWebView! private lazy var contextMenuInteraction = UIContextMenuInteraction(delegate: self) private var isFullScreenAvailable: Bool { @@ -41,7 +42,7 @@ class WebViewController: UIViewController { private var isShowingExtractedArticle = false { didSet { if isShowingExtractedArticle != oldValue { - reloadHTML() + renderPage() } } } @@ -62,7 +63,7 @@ class WebViewController: UIViewController { startArticleExtractor() } if article != oldValue { - reloadHTML() + renderPage() } } } @@ -101,6 +102,7 @@ class WebViewController: UIViewController { self.view.bottomAnchor.constraint(equalTo: webView.bottomAnchor) ]) + // Configure the tap zones self.configureTopShowBarsView() self.configureBottomShowBarsView() @@ -114,53 +116,13 @@ class WebViewController: UIViewController { // Even though page.html should be loaded into this webview, we have to do it again // to work around this bug: http://www.openradar.me/22855188 - let url = Bundle.main.url(forResource: "page", withExtension: "html")! - webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) - + self.reloadHTML() + self.view.setNeedsLayout() self.view.layoutIfNeeded() } } - - func reloadHTML() { - guard let webView = webView else { return } - - let style = ArticleStylesManager.shared.currentStyle - let rendering: ArticleRenderer.Rendering - - if let articleExtractor = articleExtractor, articleExtractor.state == .processing { - rendering = ArticleRenderer.loadingHTML(style: style) - } else if let articleExtractor = articleExtractor, articleExtractor.state == .failedToParse, let article = article { - rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) - } else if let article = article, let extractedArticle = extractedArticle { - if isShowingExtractedArticle { - rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: true) - } else { - rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) - } - } else if let article = article { - rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) - } else { - rendering = ArticleRenderer.noSelectionHTML(style: style) - } - - let templateData = TemplateData(style: rendering.style, body: rendering.html) - - let encoder = JSONEncoder() - var render = "error();" - if let data = try? encoder.encode(templateData) { - let json = String(data: data, encoding: .utf8)! - render = "render(\(json), \(restoreOffset));" - } - - restoreOffset = 0 - - WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article - webView.scrollView.setZoomScale(1.0, animated: false) - webView.evaluateJavaScript(render) - - } // MARK: Notifications @@ -293,7 +255,7 @@ extension WebViewController: ArticleExtractorDelegate { func articleExtractionDidFail(with: Error) { stopArticleExtractor() articleExtractorButtonState = .error - reloadHTML() + renderPage() } func articleExtractionDidComplete(extractedArticle: ExtractedArticle) { @@ -377,7 +339,7 @@ extension WebViewController: WKNavigationDelegate { } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - self.reloadHTML() + self.renderPage() } } @@ -460,6 +422,59 @@ private struct ImageClickMessage: Codable { private extension WebViewController { + func reloadHTML() { + let url = Bundle.main.url(forResource: "page", withExtension: "html")! + webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) + renderingTracker = 0 + } + + func renderPage() { + guard let webView = webView else { return } + + // It looks like we need to clean up the webview every once in a while by reloading it from scratch + // Otherwise it will stop responding or cause rendering artifacts. This typically only comes into + // play on the iPad where we aren't constantly pushing and popping this controller. + if (renderingTracker > 10) { + reloadHTML() + } + renderingTracker += 1 + + let style = ArticleStylesManager.shared.currentStyle + let rendering: ArticleRenderer.Rendering + + if let articleExtractor = articleExtractor, articleExtractor.state == .processing { + rendering = ArticleRenderer.loadingHTML(style: style) + } else if let articleExtractor = articleExtractor, articleExtractor.state == .failedToParse, let article = article { + rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) + } else if let article = article, let extractedArticle = extractedArticle { + if isShowingExtractedArticle { + rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: true) + } else { + rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) + } + } else if let article = article { + rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true) + } else { + rendering = ArticleRenderer.noSelectionHTML(style: style) + } + + let templateData = TemplateData(style: rendering.style, body: rendering.html) + + let encoder = JSONEncoder() + var render = "error();" + if let data = try? encoder.encode(templateData) { + let json = String(data: data, encoding: .utf8)! + render = "render(\(json), \(restoreOffset));" + } + + restoreOffset = 0 + + WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article + webView.scrollView.setZoomScale(1.0, animated: false) + webView.evaluateJavaScript(render) + + } + func finalScrollPosition() -> CGFloat { return webView.scrollView.contentSize.height - webView.scrollView.bounds.height + webView.scrollView.safeAreaInsets.bottom }