iOS WKWebView 사용

다음 예는 사용 가능한 옵션의 일부를 나타냅니다. 이러한 예는 주어진 상황에 대한 최소한의 실행 가능한 솔루션으로 간주해야 합니다. WKWebView 사용은 Google Pay 흐름 지원으로 제한되며 추가 WebView 기반 기능은 포함되지 않습니다. 프로젝트에서 제공된 솔루션을 구현할 때는 자체 판단과 프로젝트별 맞춤설정을 사용하세요.

동일한 뷰 컨트롤러에 팝업 표시

이 Swift 예시에서는 새 WebView (팝업용)가 상위 WebView를 덮는 동일한 UIViewController에 표시되는 방법을 보여줍니다. 팝업을 만들고 표시하려면 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) 함수는 전달된 webViewuiDelegate도 설정합니다. 다음은 샘플 구현입니다.

/// 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를 표시하는 방법을 보여줍니다. WKWebViewUIKit 구성요소이므로 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의 상단에 배치합니다. 팝업 닫기 이벤트에서 뷰 계층 구조에서 삭제합니다.