以下範例僅列出部分可用選項。這些範例應視為特定情況下的最低可行解決方案。
WKWebView這些範例的使用範圍僅限於支援 Google Pay 流程,不包含任何其他由 WebView 支援的功能。
在專案中導入任何提供的解決方案時,請自行判斷並進行專案專屬的自訂作業。
在同一個檢視畫面控制器中顯示彈出式視窗
這個 Swift 範例示範如何在涵蓋父項 WebView 的相同 UIViewController 中,顯示新的 WebView (適用於彈出式視窗)。 如要建立及顯示彈出式視窗,請實作 WKUIDelegate 中的下列方法:
/// Creates a new WebView for displaying a popup func webView( _ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // If the target of the navigation is a new window (popup), this property is nil guard navigationAction.targetFrame == nil else { return nil } // Creates a new WebView for a popup, and displays it in the same view controller (on the top of `mainWebView`) let popupWebView = WKWebView(frame: .zero, configuration: configuration) addWebView(popupWebView) return popupWebView }
此外,這個委派項目還有一個方法,可從畫面上移除彈出式視窗:
/// Removes the WebView from the view hierarchy and updates the UI as needed (after popup was closed) func webViewDidClose(_ webView: WKWebView) { /// Keeping the `mainWebView` on screen, and removing only popups guard webView != mainWebView else { return } webView.removeFromSuperview() }
函式 addWebView(_ webView: WKWebView) 也會為傳遞的 webView 設定 uiDelegate。以下是導入範例:
/// Adds a WebView into the view hierarchy /// Same method is being used for displaying both `mainWebView` and any popups func addWebView(_ webView: WKWebView) { webView.uiDelegate = self webView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(webView) NSLayoutConstraint.activate([ webView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), webView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) }
如果是單一檢視畫面控制器實作,則應加入「關閉」按鈕,讓使用者可以關閉彈出式視窗 (例如「服務條款」頁面)。這個按鈕的位置會因應用程式的 UI 而異。在下列範例中,按鈕會直接新增至 WebView:
/// Adds a "Close" button overlay to the top-trailing corner of a given WebView func addCloseButton(to webView: WKWebView) { let buttonSize = 24.0 let buttonMargin = 6.0 let closeAction = UIAction { [weak self] _ in self?.webViewDidClose(webView) } let closeButton = UIButton(type: .system, primaryAction: closeAction) closeButton.translatesAutoresizingMaskIntoConstraints = false var config = UIButton.Configuration.filled() config.baseBackgroundColor = .systemFill.withAlphaComponent(0.5) config.baseForegroundColor = .systemBackground config.buttonSize = .medium config.cornerStyle = .capsule config.image = UIImage(systemName: "xmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: buttonSize / 2, weight: .bold)) closeButton.configuration = config webView.addSubview(closeButton) NSLayoutConstraint.activate([ closeButton.topAnchor.constraint(equalTo: webView.safeAreaLayoutGuide.topAnchor, constant: buttonMargin), closeButton.trailingAnchor.constraint(equalTo: webView.safeAreaLayoutGuide.trailingAnchor, constant: -buttonMargin), closeButton.widthAnchor.constraint(equalToConstant: buttonSize), closeButton.heightAnchor.constraint(equalToConstant: buttonSize) ]) }
在新檢視畫面控制器中顯示彈出式視窗
這個 Objective-C 範例說明如何在新的檢視區塊控制器中顯示新的 WebView (適用於彈出式視窗),如果您的應用程式支援分頁,則可使用這個控制器。
其中一個選項是讓這個檢視畫面控制器擁有可接受外部 WKWebView 例項的初始化器:
/// Creates a view controller with a given WebView - (instancetype)initWithWebView:(WKWebView *)webView { if (self = [super init]) { self.webView = webView; } return self; }
如要建立及顯示彈出式視窗,請實作 WKUIDelegate 中的下列方法:
/// Creates a new WebView for displaying a popup - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { // If the target of the navigation is a new window (popup), this property is nil if (navigationAction.targetFrame != nil) { return nil; } // Create a new WebView for a popup WKWebView *popupWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]; // Create a new instance of `NewViewController` with a newly created WebView, and present it modally NewViewController *popupViewController = [[NewViewController alloc] initWithWebView:popupWebView]; [self presentViewController:popupViewController animated:YES completion:nil]; return popupWebView; }
此外,這個委派項目還有一個方法,可從畫面上移除彈出式視窗:
/// Dismisses the current view controller (after popup was closed) - (void)webViewDidClose:(WKWebView *)webView { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }
使用 SwiftUI 顯示彈出式視窗
這個 SwiftUI 範例示範如何在涵蓋父項 WebView 的相同 Swift 檢視區塊中,顯示新的 WebView (適用於彈出式視窗)。 由於 WKWebView 是 UIKit 元件,請將其包裝在 UIViewRepresentable 中:
/// A SwiftUI wrapper for `WKWebView` struct WebView: UIViewRepresentable { /// Underlying WebView let wkWebView = WKWebView() /// Loads a given `url` into the underlying WebView func load(url: URL) -> Self { wkWebView.load(URLRequest(url: url)) return self } /// Creates the view object representing `WKWebView` and configures its initial state func makeUIView(context: Context) -> some UIView { wkWebView.uiDelegate = context.coordinator return wkWebView } /// When the state of the app changes, SwiftUI calls this method for any changes affecting /// the corresponding UIKit viewAs an alternative, this method could be used to load the `url` /// into the WebView instead of calling `load(url:)` explicitly func updateUIView(_ uiView: UIViewType, context: Context) { } /// Creates a bridge between SwiftUI and `WKUIDelegate` func makeCoordinator() -> WKUIDelegate { /// A coordinator capable of handling `WKUIDelegate` events final class Coordinator: NSObject, WKUIDelegate { /// Main WebView which displays the `url` passed into `SwiftUISurface` let mainWebView: WebView /// Creates a coordinator with a given main WebView init(_ mainWebView: WebView) { self.mainWebView = mainWebView } /// Creates a new WebView for displaying a popup func webView( _ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { // If the target of the navigation is a new window (popup), this property is nil guard navigationAction.targetFrame == nil else { return nil } // Creates a new WebView for a popup which would use the same coordinator let popupWebView = WKWebView(frame: webView.frame, configuration: configuration) popupWebView.translatesAutoresizingMaskIntoConstraints = false popupWebView.uiDelegate = webView.uiDelegate /// Displays the newly created popup WebView on the top of a parent WebView (`mainWebView`) webView.addSubview(popupWebView) NSLayoutConstraint.activate([ popupWebView.leadingAnchor.constraint(equalTo: webView.leadingAnchor), popupWebView.topAnchor.constraint(equalTo: webView.topAnchor), popupWebView.trailingAnchor.constraint(equalTo: webView.trailingAnchor), popupWebView.bottomAnchor.constraint(equalTo: webView.bottomAnchor), ]) return popupWebView } /// Removes the WebView from the view hierarchy and updates the UI as needed (after popup was closed) func webViewDidClose(_ webView: WKWebView) { /// Keeping the `mainWebView` on screen, and removing only popups guard webView != mainWebView.wkWebView else { return } webView.removeFromSuperview() } } return Coordinator(self) } }
程式碼片段包含 WebView 的 UIViewRepresentable 包裝函式,以及可處理 WebView 委派事件的自訂 Coordinator 類別。當系統要求彈出式視窗時,會建立該視窗,並將其置於父項 WebView 的頂端。在彈出式視窗關閉事件中,系統會從檢視區塊階層中移除該事件。