Flush are rebuild web view queue when suspending and restoring the app. Issue #1563
This commit is contained in:
parent
8ed9958631
commit
dfd6be5fa6
@ -224,6 +224,7 @@
|
||||
51C452AF2265108300C03939 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; };
|
||||
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
|
||||
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
|
||||
51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */; };
|
||||
51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51CE1C0823621EDA005548FC /* RefreshProgressView.xib */; };
|
||||
51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CE1C0A23622006005548FC /* RefreshProgressView.swift */; };
|
||||
51CE1C712367721A005548FC /* testURLsOfCurrentArticle.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EADB213660A100CF2DE4 /* testURLsOfCurrentArticle.applescript */; };
|
||||
@ -1354,6 +1355,7 @@
|
||||
51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = "<group>"; };
|
||||
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
|
||||
51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrapperScriptMessageHandler.swift; sourceTree = "<group>"; };
|
||||
51CE1C0823621EDA005548FC /* RefreshProgressView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RefreshProgressView.xib; sourceTree = "<group>"; };
|
||||
51CE1C0A23622006005548FC /* RefreshProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshProgressView.swift; sourceTree = "<group>"; };
|
||||
51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineDataSource.swift; sourceTree = "<group>"; };
|
||||
@ -1969,6 +1971,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */,
|
||||
51F9F3F623DF6DB200A314FD /* ArticleIconSchemeHandler.swift */,
|
||||
51C4527E2265092C00C03939 /* ArticleViewController.swift */,
|
||||
51C266E9238C334800F53014 /* ContextMenuPreviewViewController.swift */,
|
||||
514219362352510100E07E2C /* ImageScrollView.swift */,
|
||||
@ -1977,7 +1980,7 @@
|
||||
512D554323C804DE0023FFFA /* OpenInSafariActivity.swift */,
|
||||
51AB8AB223B7F4C6008F147D /* WebViewController.swift */,
|
||||
517630222336657E00E15FFF /* WebViewProvider.swift */,
|
||||
51F9F3F623DF6DB200A314FD /* ArticleIconSchemeHandler.swift */,
|
||||
51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */,
|
||||
);
|
||||
path = Article;
|
||||
sourceTree = "<group>";
|
||||
@ -3920,6 +3923,7 @@
|
||||
51F85BF722749FA100C787DC /* UIFont-Extensions.swift in Sources */,
|
||||
51C452AF2265108300C03939 /* ArticleArray.swift in Sources */,
|
||||
51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */,
|
||||
51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */,
|
||||
51627A6B238629D8007B3B4B /* MasterFeedDataSource.swift in Sources */,
|
||||
51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */,
|
||||
5141E7392373C18B0013FF27 /* WebFeedInspectorViewController.swift in Sources */,
|
||||
|
@ -75,6 +75,7 @@ class ArticleViewController: UIViewController {
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
|
||||
let fullScreenTapZone = UIView()
|
||||
@ -190,6 +191,15 @@ class ArticleViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func contentSizeCategoryDidChange(_ note: Notification) {
|
||||
coordinator.webViewProvider.flushQueue()
|
||||
coordinator.webViewProvider.replenishQueueIfNeeded()
|
||||
if let controller = currentWebViewController {
|
||||
controller.fullReload()
|
||||
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func willEnterForeground(_ note: Notification) {
|
||||
// The toolbar will come back on you if you don't hide it again
|
||||
if AppDefaults.articleFullscreenEnabled {
|
||||
|
@ -89,7 +89,6 @@ class WebViewController: UIViewController {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(webFeedIconDidBecomeAvailable(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
|
||||
// Configure the tap zones
|
||||
configureTopShowBarsView()
|
||||
@ -118,10 +117,6 @@ class WebViewController: UIViewController {
|
||||
reloadArticleImage()
|
||||
}
|
||||
|
||||
@objc func contentSizeCategoryDidChange(_ note: Notification) {
|
||||
fullReload()
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
@objc func showBars(_ sender: Any) {
|
||||
@ -354,21 +349,6 @@ extension WebViewController: WKScriptMessageHandler {
|
||||
|
||||
}
|
||||
|
||||
class WrapperScriptMessageHandler: NSObject, WKScriptMessageHandler {
|
||||
|
||||
// We need to wrap a message handler to prevent a circlular reference
|
||||
private weak var handler: WKScriptMessageHandler?
|
||||
|
||||
init(_ handler: WKScriptMessageHandler) {
|
||||
self.handler = handler
|
||||
}
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
handler?.userContentController(userContentController, didReceive: message)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: UIViewControllerTransitioningDelegate
|
||||
|
||||
extension WebViewController: UIViewControllerTransitioningDelegate {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
25
iOS/Article/WrapperScriptMessageHandler.swift
Normal file
25
iOS/Article/WrapperScriptMessageHandler.swift
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// WrapperScriptMessageHandler.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 2/4/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
class WrapperScriptMessageHandler: NSObject, WKScriptMessageHandler {
|
||||
|
||||
// We need to wrap a message handler to prevent a circlular reference
|
||||
private weak var handler: WKScriptMessageHandler?
|
||||
|
||||
init(_ handler: WKScriptMessageHandler) {
|
||||
self.handler = handler
|
||||
}
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
handler?.userContentController(userContentController, didReceive: message)
|
||||
}
|
||||
|
||||
}
|
@ -156,3 +156,7 @@ function stopMediaPlayback() {
|
||||
element.pause();
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
window.webkit.messageHandlers.domContentLoaded.postMessage("");
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user