Loading...
Loading...
Native SwiftUI WebKit integration with the new WebView struct and WebPage observable class. Covers WebView creation from URLs, WebPage for navigation control and state management, JavaScript execution (callJavaScript with arguments and content worlds), custom URL scheme handlers, navigation management (load, reload, back/forward), navigation decisions, text search (findNavigator), content capture (snapshots, PDF generation, web archives), and configuration (data stores, user agents, JS permissions). Use when embedding web content in SwiftUI apps instead of the old WKWebView + UIViewRepresentable/NSViewRepresentable bridge pattern. This is a brand new API — do NOT use the old WKWebView wrapping approach.
npx skill4agent add makgunay/claude-swift-skills swiftui-webkitWebViewWKWebViewWKWebViewUIViewRepresentableNSViewRepresentableWebViewWKWebViewConfigurationWebPage.ConfigurationWKNavigationDelegateWebPage.NavigationDecidingevaluateJavaScript(_:)page.callJavaScript(_:)WKUserContentControllercallJavaScriptimport SwiftUI
import WebKit
struct ContentView: View {
var body: some View {
WebView(url: URL(string: "https://www.apple.com"))
.frame(height: 400)
}
}struct BrowserView: View {
@State private var page = WebPage()
var body: some View {
NavigationStack {
WebView(page)
.navigationTitle(page.title)
}
.onAppear {
if let url = URL(string: "https://www.apple.com") {
let _ = page.load(URLRequest(url: url))
}
}
}
}struct SearchableWebView: View {
@State private var searchVisible = true
var body: some View {
WebView(url: URL(string: "https://www.apple.com"))
.findNavigator(isPresented: $searchVisible)
}
}var config = WebPage.Configuration()
config.loadsSubresources = true
config.defaultNavigationPreferences.allowsContentJavaScript = true
config.websiteDataStore = .default() // Persistent
// config.websiteDataStore = .nonPersistent() // Ephemeral
let page = WebPage(configuration: config)
page.customUserAgent = "MyApp/1.0"// URL
page.load(URLRequest(url: url))
// HTML string
page.load(html: "<h1>Hello</h1>", baseURL: URL(string: "https://example.com")!)
// Data
page.load(data, mimeType: "text/html", characterEncoding: .utf8, baseURL: baseURL)
// Navigation
page.reload(fromOrigin: false)
page.stopLoading()
// Back/Forward
if let backItem = page.backForwardList.backItem {
page.load(backItem)
}// Basic
let title = try await page.callJavaScript("document.title")
// With arguments
let script = """
function findElement(selector) {
return document.querySelector(selector)?.textContent;
}
return findElement(selector);
"""
let result = try await page.callJavaScript(script, arguments: ["selector": ".main-content h1"])
// In specific content world
import WebKit
let result = try await page.callJavaScript("document.title", contentWorld: .page).onChange(of: page.currentNavigationEvent) { _, newEvent in
if let event = newEvent {
switch event.state {
case .started: isLoading = true
case .finished, .failed: isLoading = false
default: break
}
}
}struct MyNavigationDecider: WebPage.NavigationDeciding {
func decidePolicyFor(navigationAction: WebPage.NavigationAction) async -> WebPage.NavigationPreferences? {
if let url = navigationAction.request.url, url.host == "blocked.com" {
return nil // Block navigation
}
var prefs = WebPage.NavigationPreferences()
prefs.allowsContentJavaScript = true
return prefs
}
func decidePolicyFor(navigationResponse: WebPage.NavigationResponse) async -> Bool {
if let http = navigationResponse.response as? HTTPURLResponse {
return http.statusCode == 200
}
return true
}
}
let page = WebPage(configuration: config, navigationDecider: MyNavigationDecider())struct MySchemeHandler: URLSchemeHandler {
func start(task: URLSchemeTask) {
guard let url = task.request.url, url.scheme == "myapp" else {
task.didFailWithError(URLError(.badURL)); return
}
let html = "<html><body><h1>Custom Content</h1></body></html>"
let response = URLResponse(url: url, mimeType: "text/html",
expectedContentLength: -1, textEncodingName: "utf-8")
task.didReceive(response)
task.didReceive(Data(html.utf8))
task.didFinish()
}
func stop(task: URLSchemeTask) { }
}
var config = WebPage.Configuration()
config.setURLSchemeHandler(MySchemeHandler(), forURLScheme: "myapp")// Snapshot
let image = try await page.snapshot(WKSnapshotConfiguration())
// PDF
let pdfData = try await page.pdf(configuration: WKPDFConfiguration())
// Web Archive
let archiveData = try await page.webArchiveData()WebView(url: url)
.webViewBackForwardNavigationGestures(.disabled)
.webViewMagnificationGestures(.enabled)
.webViewLinkPreviews(.disabled)
.webViewTextSelection(.enabled)
.webViewContentBackground(.color(.systemBackground))
.webViewElementFullscreenBehavior(.enabled)