spb/prisme Public MIT
Navigateur iOS intelligent — chaque page comprise localement avant d'être affichée. SwiftUI · WebKit · Foundation Models, 100% on-device.
Swift 96.7%
JavaScript 3.3%
1//2// WebViewPool.swift3// Prisme4//5// Author: Simon-Pierre Boucher <contact@spboucher.ai>6//78import Foundation9import WebKit1011/// Reusable `WKWebView` instances, partitioned by identity container.12/// Never instantiate one web view per tab (CLAUDE.md §8): tabs check a view13/// out while visible and check it back in when they leave the screen.14@MainActor15final class WebViewPool {16 private static let maxIdlePerContainer = 31718 private let containers: IdentityContainerStore19 private let rules: ContentRuleManager2021 private var idle: [IdentityContainer.ID: [WKWebView]] = [:]22 /// Weak set of every view we ever vended, so freshly compiled content23 /// rules can be applied to views already on screen.24 private let live = NSHashTable<WKWebView>.weakObjects()2526 init(containers: IdentityContainerStore, rules: ContentRuleManager) {27 self.containers = containers28 self.rules = rules29 }3031 func checkout(for containerID: IdentityContainer.ID) -> WKWebView {32 if let reused = idle[containerID]?.popLast() {33 return reused34 }35 let webView = makeWebView(for: containerID)36 live.add(webView)37 return webView38 }3940 func checkin(_ webView: WKWebView, containerID: IdentityContainer.ID) {41 webView.stopLoading()42 var stack = idle[containerID] ?? []43 guard stack.count < Self.maxIdlePerContainer else { return }44 stack.append(webView)45 idle[containerID] = stack46 }4748 /// Apply a compiled rule list to all current and future web views.49 func apply(_ ruleList: WKContentRuleList) {50 for webView in live.allObjects {51 webView.configuration.userContentController.add(ruleList)52 }53 }5455 /// Extractor source is read once; it only defines functions, so the56 /// injection cost at documentEnd is negligible (CLAUDE.md §8).57 private static let extractorSource: String? = {58 guard let url = Bundle.main.url(forResource: "extractor", withExtension: "js") else { return nil }59 return try? String(contentsOf: url, encoding: .utf8)60 }()6162 private func makeWebView(for containerID: IdentityContainer.ID) -> WKWebView {63 let configuration = WKWebViewConfiguration()64 configuration.websiteDataStore = containers.dataStore(for: containerID)65 configuration.allowsInlineMediaPlayback = true66 if let ruleList = rules.ruleList {67 configuration.userContentController.add(ruleList)68 }69 if let source = Self.extractorSource {70 configuration.userContentController.addUserScript(71 WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)72 )73 }7475 let webView = PrismeWebView(frame: .zero, configuration: configuration)76 webView.allowsBackForwardNavigationGestures = true77 webView.isFindInteractionEnabled = true78 webView.scrollView.contentInsetAdjustmentBehavior = .always79 return webView80 }81}82