In the following code, I'm loading HTML pages into a WKWebView, only to get the contents of their first H1 tag. Other than what *any type of page* renders in its first H1 tag, I don't need anything else...
Is there perhaps a more efficient/performant way besides initializing a WKWebView for this?
(the .frame(width: 0, height: 0) modifier annoys me a bit, as well)
Is there perhaps a more efficient/performant way besides initializing a WKWebView for this?
(the .frame(width: 0, height: 0) modifier annoys me a bit, as well)
Code Block swiftimport SwiftUIimport WebKitimport WebView /* add this Swift Package Dependency https://github.com/kylehickinson/SwiftUI-WebView */struct ContentView: View { @StateObject private var viewModel: ContentViewModel init() { let viewModel = ContentViewModel() _viewModel = StateObject(wrappedValue: viewModel) } var body: some View { VStack(spacing: 30) { Button("load plain H1 tag") { viewModel.webViewStore.webView.loadHTMLString("<h1>H1</h1>", baseURL: nil) } Button("load body where h1 is appended by JavaScript") { viewModel.webViewStore.webView.loadHTMLString("<body></body><script>(function(){ let h1 = document.createElement('h1'); h1.textContent = 'H1 JavaScript'; document.body.appendChild(h1); })()</script>", baseURL: nil) } Button("load apple.com/iphone") { viewModel.webViewStore.webView.load(URLRequest(url: URL(string: "https://apple.com/iphone")!)) } Button("load hackingwithswift.com") { viewModel.webViewStore.webView.load(URLRequest(url: URL(string: "https://hackingwithswift.com")!)) } Group { Text("the first H1 element on ") + Text(viewModel.webViewStore.webView.url?.description ?? "...").foregroundColor(.accentColor) + Text(" is") } .font(.subheadline) Text(viewModel.h1) .font(.largeTitle) .foregroundColor(.green) WebView(webView: viewModel.webViewStore.webView) .frame(width: 0, height: 0) } }}class ContentViewModel: NSObject, WKScriptMessageHandler, ObservableObject { @Published var h1 = "..." @Published var webViewStore: WebViewStore override init() { let userContentController = WKUserContentController() let configuration = WKWebViewConfiguration() let userScript = WKUserScript( source: """ function elementReady(selector) { return new Promise((resolve, reject) => { let el = document.querySelector(selector) if (el) { resolve(el) } new MutationObserver((mutationRecords, observer) => { Array.from(document.querySelectorAll(selector)).forEach((element) => { resolve(element) observer.disconnect() }) }).observe(document.documentElement, { childList: true, subtree: true, }) }) } elementReady("h1").then((titleElement) => { window.webkit.messageHandlers.h1.postMessage(titleElement.textContent) }) """, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: .defaultClient ) userContentController.addUserScript(userScript) configuration.userContentController = userContentController let webView = WKWebView(frame: .zero, configuration: configuration) webViewStore = WebViewStore(webView: webView) super.init() userContentController.add(self, contentWorld: .defaultClient, name: "h1") } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "h1" { h1 = message.body as! String } }}struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() }}