mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Flush are rebuild web view queue when suspending and restoring the app. Issue #1563
This commit is contained in:
@@ -13,6 +13,10 @@ import WebKit
|
||||
/// Keep a queue of WebViews where we've already done a trivial load so that by the time we need them in the UI, they're past the flash-to-shite part of their lifecycle.
|
||||
class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
|
||||
private struct MessageName {
|
||||
static let domContentLoaded = "domContentLoaded"
|
||||
}
|
||||
|
||||
let articleIconSchemeHandler: ArticleIconSchemeHandler
|
||||
|
||||
private let minimumQueueDepth = 3
|
||||
@@ -26,7 +30,31 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
articleIconSchemeHandler = ArticleIconSchemeHandler(coordinator: coordinator)
|
||||
super.init()
|
||||
viewController.view.insertSubview(queue, at: 0)
|
||||
|
||||
replenishQueueIfNeeded()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc func didEnterBackground() {
|
||||
flushQueue()
|
||||
}
|
||||
|
||||
@objc func willEnterForeground() {
|
||||
replenishQueueIfNeeded()
|
||||
}
|
||||
|
||||
func flushQueue() {
|
||||
queue.subviews.forEach { $0.removeFromSuperview() }
|
||||
waitingForFirstLoad = true
|
||||
}
|
||||
|
||||
func replenishQueueIfNeeded() {
|
||||
while queue.subviews.count < minimumQueueDepth {
|
||||
let webView = WKWebView(frame: .zero, configuration: buildConfiguration())
|
||||
enqueueWebView(webView)
|
||||
}
|
||||
}
|
||||
|
||||
func dequeueWebView(completion: @escaping (WKWebView) -> ()) {
|
||||
@@ -42,11 +70,10 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
webView.navigationDelegate = self
|
||||
webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.domContentLoaded)
|
||||
queue.insertSubview(webView, at: 0)
|
||||
|
||||
webView.loadFileURL(ArticleRenderer.page.url, allowingReadAccessTo: ArticleRenderer.page.baseURL)
|
||||
|
||||
}
|
||||
|
||||
// MARK: WKNavigationDelegate
|
||||
@@ -63,30 +90,39 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
}
|
||||
|
||||
private func replenishQueueIfNeeded() {
|
||||
while queue.subviews.count < minimumQueueDepth {
|
||||
let preferences = WKPreferences()
|
||||
preferences.javaScriptCanOpenWindowsAutomatically = false
|
||||
preferences.javaScriptEnabled = true
|
||||
// MARK: WKScriptMessageHandler
|
||||
|
||||
let configuration = WKWebViewConfiguration()
|
||||
configuration.preferences = preferences
|
||||
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
|
||||
configuration.allowsInlineMediaPlayback = true
|
||||
configuration.mediaTypesRequiringUserActionForPlayback = .video
|
||||
configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme)
|
||||
|
||||
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||
enqueueWebView(webView)
|
||||
extension WebViewProvider: WKScriptMessageHandler {
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
switch message.name {
|
||||
case MessageName.domContentLoaded:
|
||||
if waitingForFirstLoad {
|
||||
waitingForFirstLoad = false
|
||||
if let completion = waitingCompletionHandler {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.completeRequest(completion: completion)
|
||||
self.waitingCompletionHandler = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private func completeRequest(completion: @escaping (WKWebView) -> ()) {
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private extension WebViewProvider {
|
||||
|
||||
func completeRequest(completion: @escaping (WKWebView) -> ()) {
|
||||
if let webView = queue.subviews.last as? WKWebView {
|
||||
webView.removeFromSuperview()
|
||||
webView.navigationDelegate = nil
|
||||
webView.configuration.userContentController.removeScriptMessageHandler(forName: MessageName.domContentLoaded)
|
||||
replenishQueueIfNeeded()
|
||||
completion(webView)
|
||||
return
|
||||
@@ -96,5 +132,19 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
let webView = WKWebView(frame: .zero)
|
||||
completion(webView)
|
||||
}
|
||||
|
||||
|
||||
func buildConfiguration() -> WKWebViewConfiguration {
|
||||
let preferences = WKPreferences()
|
||||
preferences.javaScriptCanOpenWindowsAutomatically = false
|
||||
preferences.javaScriptEnabled = true
|
||||
|
||||
let configuration = WKWebViewConfiguration()
|
||||
configuration.preferences = preferences
|
||||
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
|
||||
configuration.allowsInlineMediaPlayback = true
|
||||
configuration.mediaTypesRequiringUserActionForPlayback = .video
|
||||
configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme)
|
||||
|
||||
return configuration
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user