iOS
Setting Up the WebView
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
// Define the specific UIView subclass we are representing
typealias UIViewType = WKWebView
let urlString: String
func makeUIView(context: Context) -> WKWebView {
// Configuration
let webViewConfiguration = WKWebViewConfiguration()
// Allow video playback inline
webViewConfiguration.allowsInlineMediaPlayback = true
// Allow PiP for video
webViewConfiguration.allowsPictureInPictureMediaPlayback = true
// Allow JS to enter fullscreen
webViewConfiguration.preferences.isElementFullscreenEnabled = true
// Allow media to play without user gesture (use with caution, respect user settings)
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
// JavaScript Injection
let scriptSource = """
window._lscLocalThemeOptions = { playerDismissCtaState: "enabled" };
"""
let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let contentController = WKUserContentController()
contentController.addUserScript(userScript)
// Register the message handler with the coordinator
contentController.add(context.coordinator, name: "MessageFromLiSA")
webViewConfiguration.userContentController = contentController
// Create WKWebView
// Use .zero frame; SwiftUI will manage the actual frame size
let webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
// Only include this setting in Debug builds
#if DEBUG
if #available(iOS 16.4, *) {
// Explicitly allow inspection for Debug builds on iOS 16.4+
// Log confirmation
print("Setting webView.isInspectable = true")
// Set on the webView instance
webView.isInspectable = true
}
#endif
// Set background colors (optional, black might hide loading issues initially)
// Consider using .clear or removing these if the webpage has its own background
webView.backgroundColor = .black
webView.scrollView.backgroundColor = .black
// Can help if you want SwiftUI background to show through
webView.isOpaque = false
webView.scrollView.contentInsetAdjustmentBehavior = .never
// Set Delegates
webView.navigationDelegate = context.coordinator
// Needed for things like JavaScript alerts or window opening
webView.uiDelegate = context.coordinator
// Store reference in Coordinator
// Keep a reference if coordinator needs to access webView later
context.coordinator.webView = webView
// Initial Load
// Load the initial URL directly in makeUIView
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
request.cachePolicy = .useProtocolCachePolicy
webView.load(request)
}
// Return the WKWebView directly
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
// The `uiView` parameter *is* the WKWebView because we set UIViewType
// Check if the urlString prop has changed and reload if necessary
if let currentURL = webView.url?.absoluteString, currentURL == urlString {
// URL hasn't changed, do nothing
return
}
// URL string has changed, load the new one
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
webView.load(request)
}
}
func makeCoordinator() -> Coordinator {
// Pass the WebView struct itself if needed
Coordinator(self)
}
// Coordinator
// Handles callbacks from the WKWebView
class Coordinator: NSObject, WKScriptMessageHandler, WKNavigationDelegate, WKUIDelegate {
// Reference back to the SwiftUI view
var parent: WebView
// Weak reference maybe better if lifecycle allows?
var webView: WKWebView?
init(_ parent: WebView) {
self.parent = parent
}
// WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "MessageFromLiSA" {
// Handle message from JavaScript
print("Received message from LiSA: \(message.body)")
// You could trigger actions in your SwiftUI view here if needed,
// e.g., using @State variables passed down or Combine publishers.
}
}
// WKNavigationDelegate (Example Methods)
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("WebView did finish loading")
// You could update SwiftUI state here, e.g., hide a loading indicator
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("WebView failed navigation: \(error.localizedDescription)")
// Handle loading errors
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print("WebView failed provisional navigation: \(error.localizedDescription)")
// Handle initial loading errors (e.g., server not found)
}
// WKUIDelegate (Optional - Add methods as needed)
// Example: Handle JavaScript window.open()
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
// If the request is a main frame navigation, open in Safari/default browser
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
// Prevents opening a new webview window within the app
return nil
}
}
}Using the WebView in SwiftUI
Last updated