fix: pre-warm WebKit engine when Reader tab loads
First WKWebView creation in a session is slow (~2-3s) because iOS lazily initializes the WebKit rendering engine. WebKitWarmer creates a hidden 1x1 WKWebView with empty HTML on Reader tab load, forcing the engine to initialize. Subsequent article opens are instant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,35 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WebKit
|
import WebKit
|
||||||
|
|
||||||
|
// MARK: - WebKit Pre-warmer
|
||||||
|
|
||||||
|
/// Pre-warms the WebKit rendering engine on first use.
|
||||||
|
/// Call `WebKitWarmer.shared.warmUp()` early (e.g. when Reader tab loads)
|
||||||
|
/// so the first article open is instant.
|
||||||
|
final class WebKitWarmer {
|
||||||
|
static let shared = WebKitWarmer()
|
||||||
|
|
||||||
|
private var warmedUp = false
|
||||||
|
private var warmView: WKWebView?
|
||||||
|
|
||||||
|
func warmUp() {
|
||||||
|
guard !warmedUp else { return }
|
||||||
|
warmedUp = true
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let config = WKWebViewConfiguration()
|
||||||
|
let wv = WKWebView(frame: CGRect(x: 0, y: 0, width: 1, height: 1), configuration: config)
|
||||||
|
wv.loadHTMLString("<html><body></body></html>", baseURL: nil)
|
||||||
|
// Hold reference briefly to ensure WebKit initializes
|
||||||
|
self.warmView = wv
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||||
|
self.warmView = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Article Web View
|
||||||
|
|
||||||
struct ArticleWebView: UIViewRepresentable {
|
struct ArticleWebView: UIViewRepresentable {
|
||||||
let html: String
|
let html: String
|
||||||
@Binding var contentHeight: CGFloat
|
@Binding var contentHeight: CGFloat
|
||||||
@@ -49,7 +78,6 @@ struct ArticleWebView: UIViewRepresentable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||||
// Measure content height after render
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
webView.evaluateJavaScript("document.body.scrollHeight") { [weak self] result, _ in
|
webView.evaluateJavaScript("document.body.scrollHeight") { [weak self] result, _ in
|
||||||
if let height = result as? CGFloat, height > 0 {
|
if let height = result as? CGFloat, height > 0 {
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ struct ReaderTabView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.task {
|
.task {
|
||||||
|
WebKitWarmer.shared.warmUp()
|
||||||
await vm.loadInitial()
|
await vm.loadInitial()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user