Utiliser WKWebView sur iOS

Les exemples suivants représentent un sous-ensemble des options disponibles. Ces exemples doivent être considérés comme des solutions viables minimales pour des circonstances données. L'utilisation de WKWebView dans ces exemples est limitée à la compatibilité avec le flux Google Pay et n'inclut aucune autre fonctionnalité basée sur WebView. Faites preuve de discernement et utilisez des personnalisations spécifiques à votre projet lorsque vous implémentez l'une des solutions proposées dans votre projet.

Afficher un pop-up dans le même contrôleur de vue

Cet exemple Swift montre comment une nouvelle WebView (pour un pop-up) peut être affichée dans le même UIViewController couvrant une WebView parente. Pour créer et afficher un pop-up, implémentez la méthode suivante à partir de 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
}
  

Voici une autre méthode de ce délégué qui permet de supprimer un pop-up de l'écran :

/// 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()
}
  

La fonction addWebView(_ webView: WKWebView) définit également le uiDelegate pour un webView transmis. Voici un exemple d'implémentation :

/// 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)
  ])
}
  

Pour les implémentations de contrôleur de vue unique, un bouton "Fermer" doit être ajouté pour permettre aux utilisateurs de fermer les pop-ups (par exemple, une page "Conditions d'utilisation"). Ce bouton peut être placé à différents endroits en fonction de l'interface utilisateur de l'application. Dans l'exemple suivant, le bouton est ajouté directement à la 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)
  ])
}
  

Afficher un pop-up dans un nouveau contrôleur de vue

Cet exemple Objective-C montre comment une nouvelle WebView (pour un pop-up) peut être affichée dans un nouveau contrôleur de vue (qui peut être utilisé si votre application prend en charge les onglets). Comme l'une des options, ce contrôleur de vue peut avoir un initialiseur qui accepte une instance WKWebView externe :

/// Creates a view controller with a given WebView
- (instancetype)initWithWebView:(WKWebView *)webView {
  if (self = [super init]) {
    self.webView = webView;
  }
  return self;
}
  

Pour créer et afficher un pop-up, implémentez la méthode suivante à partir de 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;
}
  

Voici une autre méthode de ce délégué qui permet de supprimer un pop-up de l'écran :

/// Dismisses the current view controller (after popup was closed)
- (void)webViewDidClose:(WKWebView *)webView {
  [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
  

Afficher un pop-up à l'aide de SwiftUI

Cet exemple SwiftUI montre comment une nouvelle WebView (pour un pop-up) peut être affichée dans la même vue Swift couvrant une WebView parente. Comme WKWebView est un composant UIKit, encapsulez-le dans 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)
  }
}
  

L'extrait de code inclut à la fois le wrapper UIViewRepresentable pour une WebView et une classe Coordinator personnalisée capable de gérer les événements délégués WebView. Lorsqu'un pop-up est demandé, il est créé et placé en haut d'une WebView parente. Lors d'un événement de fermeture de pop-up, il est supprimé de la hiérarchie des vues.