概述
崇禎年間,華山派武學雖盛,卻在應對江湖新局時漸顯頹勢;如今 SwiftUI 江湖亦是如此 ——WWDC 25 之前,若要在 SwiftUI 中顯示網頁,開發者恰似袁承志初闖江湖,縱有一身本領,卻苦無稱手兵刃。
直到那柄 “金蛇劍” 般的全新 WebView 橫空出世,才讓網頁顯示之道豁然開朗。
在本篇武學大家談中,各位少俠將學到如下內容:
- 概述
- 一、往昔困局:華山舊功難破迷陣
- 二、金蛇出洞:WWDC 25 的 WebView 新法
- 1. 初窺門徑:基礎網頁加載
- 2. 內功心法:WebPage 狀態管理
- 3. 奇門絕技:JS 交互與平臺適配
- 三、江湖展望:金蛇之后再無鈍劍
想得到那柄可以橫掃武林的神兵利器金蛇劍嗎?那還等什么?讓我們馬上開始尋“劍”之旅吧!
Let’s go!!!😉
一、往昔困局:華山舊功難破迷陣
想當年,SwiftUI 自身并無網頁顯示的獨門心法,開發者們只得借 UIKit 的 WKWebView 這柄 “鈍劍”,再輔以UIViewRepresentable
為鞘,方能勉強施展。
這般操作,猶如袁承志在華山練劍時,需先扎三年馬步 —— 基礎雖牢,卻失之滯澀。
且看這套 “華山入門劍法”:
import SwiftUI
import WebKit// 以UIViewRepresentable為橋,連接SwiftUI與WKWebView
struct WebViewWrapper: UIViewRepresentable {let url: URL?func makeUIView(context: Context) -> WKWebView {return WKWebView()}func updateUIView(_ uiView: WKWebView, context: Context) {guard let url = url else { return }uiView.load(URLRequest(url: url))}
}// 實戰時需如此調用,恰似執鈍劍闖敵營
struct ContentView: View {var body: some View {WebViewWrapper(url: URL(string: "https://apple.com")).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)}
}
這套功夫雖能御敵,卻有三大弊端:
- 其一,
updateUIView
反復調用時易生錯亂,好比劍法中 “劍招互礙”; - 其二,網頁狀態監聽需另設代理,猶如練劍時還要分心護脈;
- 其三,與 SwiftUI 狀態管理結合時,常現 “內力相沖” 之象 —— 稍有不慎便會數據錯亂。
二、金蛇出洞:WWDC 25 的 WebView 新法
正當開發者們困于舊法之時,WWDC 25 恰似一場武林大會,蘋果突然亮出 “金蛇劍”——SwiftUI 原生 WebView 橫空出世!此劍一出,如金蛇郎君夏雪宜重現江湖,招式靈動,渾然天成,將網頁顯示之道推向新境。
1. 初窺門徑:基礎網頁加載
新 WebView 的基礎用法,恰似袁承志初得金蛇劍時的隨手一揮,看似簡單卻暗藏玄機:
import SwiftUI
import WebKitstruct ContentView: View {// 直接使用URL初始化,無需繁瑣包裝var body: some View {WebView(url: URL(string: "https://apple.com")).navigationTitle("金蛇洞").edgesIgnoringSafeArea(.bottom)}
}
這般代碼,較之舊法省去近八成冗余,正如金蛇劍法 “險、奇、快” 之妙 —— 無需再寫UIViewRepresentable
的橋接代碼,無需手動管理 WebView 生命周期,SwiftUI 自會料理妥當。
真乃嗚呼快哉!
2. 內功心法:WebPage 狀態管理
若要深入掌控網頁狀態,需修習 “金蛇秘籍”——WebPage
類。此物如同袁承志從山洞中所得的金蛇錐譜,將網頁的標題、URL、加載進度等信息盡收其中:
import SwiftUI
import WebKit
internal import Combine// 實戰運用:將心法與招式結合
struct ContentView: View {@State private var page = WebPage()@State private var id: WebPage.NavigationID?@State private var isLoading = false@State private var event: WebPage.NavigationEvent?var body: some View {NavigationStack {WebView(page).navigationTitle(page.title).toolbar {ToolbarItem(placement: .primaryAction) {Button(action: {page.reload()}) {Image(systemName: "arrow.counterclockwise")}}ToolbarItem(placement: .topBarLeading) {if isLoading {ProgressView()}}}.onChange(of: page.isLoading) { _, new inisLoading = new}.onReceive(page.currentNavigationEvent.publisher) { event inguard event.navigationID == id else { return }switch event.kind {case let .failed(underlyingError: error):print(error.localizedDescription)case .finished:print("網頁加載完畢")default:break}}.task {let request = URLRequest(url: .init(string: "https://blog.csdn.net/mydo")!)id = page.load(request)}}}
}
此處關鍵在于@Published
屬性 —— 當網頁標題變化時,導航欄會如響應內力般自動更新;進度條則像金蛇吐信般實時菊花旋轉:
這般狀態同步,較舊法中手動綁定NotificationCenter
的操作,可謂 “化繁為簡,返璞歸真”。
3. 奇門絕技:JS 交互與平臺適配
新 WebView 最令人稱道之處,莫過于對 JavaScript 交互的 “化骨綿掌” 式處理。
昔日要在 Swift 與 JS 間傳遞數據,需寫十數行橋接代碼,如同袁承志在華山與溫家五老纏斗時的狼狽;如今卻能一劍破局:
// 實戰運用:將心法與招式結合
struct ContentView: View {@State private var page = WebPage()@State private var id: WebPage.NavigationID?@State private var isLoading = false@State private var event: WebPage.NavigationEvent?@State private var titleFromJS: String?var body: some View {NavigationStack {WebView(page).navigationTitle(page.title).toolbar {ToolbarItemGroup {Button {Task {if let jsResult = try? await page.callJavaScript("""return document.title;"""), let title = jsResult as? String {titleFromJS = title}}} label: {Image(systemName: "figure.run")}Button {Task {try? await page.callJavaScript("""document.body.style.backgroundColor = 'gold'""")}} label: {Image(systemName: "figure.cricket")}Button(action: {page.reload()}) {Image(systemName: "arrow.counterclockwise")}}ToolbarItem(placement: .topBarLeading) {if isLoading {ProgressView()}}}.onChange(of: page.isLoading) { _, new inisLoading = new}.onReceive(page.currentNavigationEvent.publisher) { event inguard event.navigationID == id else { return }switch event.kind {case let .failed(underlyingError: error):print(error.localizedDescription)case .finished:print("網頁加載完畢")default:break}}.task {let request = URLRequest(url: .init(string: "https://blog.csdn.net/mydo")!)id = page.load(request)}.safeAreaInset(edge: .top) {if let title = titleFromJS {Text(title).font(.title2).padding().background(.thinMaterial.opacity(0.66), in: RoundedRectangle(cornerRadius: 15))}}}}
}
在上面的代碼中,我們用 JavaScript 做了兩件事:
- 動態實時獲取到了網頁的標題;
- 將網頁背景設置為金色;
此等操作,恰似金蛇郎君以金蛇錐破敵甲胄 —— 直接穿透 Swift 與 JS 的壁壘。
更妙者,新 WebView 對各平臺特性的適配,如 visionOS 的 “看向滾動” 功能,只需一行修飾符即可大功告成:
WebView(webView: page.webView)#if os(VisionOS)// 開啟 VisionOS 滾動輸入”通天眼“.webViewScrollInputBehavior(.enabled, for: .look)#endif.scrollBounceBehavior(.basedOnSize) // 滾動反饋如"踏雪無痕"
三、江湖展望:金蛇之后再無鈍劍
回首 SwiftUI 的網頁顯示之道,恰似袁承志的武學進階:從華山派的循規蹈矩,到金蛇劍法的靈動不羈,再到融會貫通自成一派。
WWDC 25 推出的新 WebView,不僅解決了舊法中的 “招式沉冗” 之弊,更將 SwiftUI 的聲明式編程理念推向新高度。
正如金蛇劍在袁承志手中終成一代傳奇,這套新 WebView API 亦將成為開發者闖蕩網頁江湖的不二之選。
畢竟,真正的好功夫,從來都是 “大道至簡,大巧若拙”—— 能以三兩行代碼辦妥之事,何必耗費十數行力氣?此乃 WWDC 25 留給 SwiftUI 開發者的最大啟示,亦是江湖不變之真理。
那么,各位少俠看到這里又作何感想呢?
感謝寶子們的觀看,再會啦!😎