Prendre en charge plusieurs fenêtres et les pliables

Les applications compatibles avec le mode multifenêtre sur iPad ou qui s'exécutent sur des appareils pliables, comme l'iPhone Duo, peuvent afficher l'UI sur des tailles de fenêtre et des configurations d'écran dynamiques. Sur iPad, les utilisateurs peuvent interagir avec plusieurs copies simultanées de l'interface utilisateur d'une application et redimensionner les fenêtres. Sur les appareils pliables, l'état de pliage de l'appareil détermine l'écran actif. Lorsqu'il est déplié, l'appareil utilise l'écran intérieur plus grand. Lorsqu'il est plié, l'appareil utilise l'écran extérieur plus petit.

Ce guide explique comment charger et afficher des annonces dans des environnements multifenêtres et sur des écrans pliables.

Prérequis

Avant de commencer, procédez comme suit :

Définir la scène de la fenêtre dans une demande d'annonce

Pour recevoir une annonce qui s'adapte à une fenêtre ou à un affichage actif spécifique, attribuez l'objet UIWindowScene actif à la propriété scene de l'objet GADRequest. Google Mobile Ads SDK renvoie une annonce dimensionnée pour cette scène. Dans SwiftUI, interrogez les scènes connectées pour la scène de fenêtre active au premier plan.

L'exemple suivant configure la scène de la fenêtre, charge une annonce interstitielle en cas de réussite et consigne un message d'erreur en cas d'échec :

Swift

func loadInterstitial() async {
  let request = Request()
  request.scene = view.window?.windowScene

  do {
    interstitial = try await InterstitialAd.load(
      with: "ca-app-pub-3940256099942544/4411468910", request: request)
  } catch {
    print("Failed to load interstitial ad with error: \(error.localizedDescription)")
  }
}

SwiftUI

func loadInterstitial() async {
  let request = Request()
  request.scene =
    UIApplication.shared.connectedScenes
    .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene

  do {
    let _ = try await InterstitialAd.load(
      with: "ca-app-pub-3940256099942544/4411468910", request: request)
  } catch {
    print("Failed to load interstitial ad with error: \(error.localizedDescription)")
  }
}

Objective-C

- (void)loadInterstitial {
  GADRequest *request = [GADRequest request];
  request.scene = self.view.window.windowScene;

  [GADInterstitialAd
       loadWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910"
                request:request
      completionHandler:^(GADInterstitialAd *ad, NSError *error) {
        if (error) {
          NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]);
          return;
        }
        self.interstitial = ad;
      }];
}

En mode test, les demandes d'annonces échouent avec l'erreur suivante si votre application multi-scène demande une annonce sans transmettre de scène :

<Google> Invalid Request. The GADRequest scene property should be set for
applications that support multi-scene. Treating the unset property as an error
while in test mode.

En mode production, la demande d'annonce est satisfaite, mais la présentation de l'annonce échoue si elle est présentée dans une fenêtre plus petite que la taille du contenu de l'annonce :

<Google> Ad cannot be presented. The full screen ad content size exceeds the current window size.

Créer la demande d'annonce

Lors de l'envoi de demandes d'annonces, les applications multiscènes nécessitent une scène de fenêtre valide. Lorsque la scène de la fenêtre est renseignée, créez des demandes d'annonces à l'aide de la méthode viewDidAppear. Nous vous recommandons de procéder ainsi, car une vue n'est pas encore ajoutée à une fenêtre dans la méthode viewDidLoad.

Bien que vous puissiez appeler la méthode viewDidAppear plusieurs fois au cours du cycle de vie d'une application, vous devez encapsuler la demande d'annonce dans un indicateur booléen pour qu'elle ne s'exécute qu'une seule fois.

L'exemple suivant initialise la demande d'annonce dans la méthode viewDidAppear :

Swift

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  if !requestInitialized {
    Task {
      await loadInterstitial()
    }
    requestInitialized = true
  }
}

Objective-C

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  if (!_requestInitialized) {
    [self loadInterstitial];
    _requestInitialized = YES;
  }
}

Gérer le redimensionnement de la fenêtre

Les dimensions de la fenêtre changent lorsque les utilisateurs redimensionnent les scènes sur iPad ou plient et déplient un appareil pliable tel que l'iPhone Duo. Lorsque la taille de la fenêtre change, vérifiez que les annonces chargées s'adaptent aux nouvelles dimensions et actualisez-les si nécessaire.

Pour vérifier que les annonces chargées correspondent aux dimensions mises à jour, utilisez l'une des méthodes suivantes :

Annonces plein écran

Pour vérifier si une annonce en plein écran chargée reste valide pour la taille de fenêtre ou l'état de pliage mis à jour, utilisez la méthode canPresentFromRootViewController:error:. Si la vérification échoue, chargez une annonce dimensionnée pour la scène mise à jour.

L'exemple suivant vérifie si une annonce interstitielle peut s'afficher après une transition de taille et la recharge si nécessaire :

Swift

override func viewWillTransition(
  to size: CGSize,
  with coordinator: UIViewControllerTransitionCoordinator
) {
  super.viewWillTransition(to: size, with: coordinator)

  coordinator.animate(alongsideTransition: nil) { [weak self] _ in
    guard let self else { return }
    do {
      try self.interstitial?.canPresent(from: self)
    } catch {
      Task {
        await self.loadInterstitial()
      }
    }
  }
}

Objective-C

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

  [coordinator
      animateAlongsideTransition:nil
                      completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
                        if (![self.interstitial canPresentFromRootViewController:self error:nil]) {
                          [self loadInterstitial];
                        }
                      }];
}

Gérez le redimensionnement de la fenêtre et les transitions de pliage de la même manière que la rotation de l'appareil. Limitez les vues de la bannière à la propriété safeAreaLayoutGuide. Ce processus permet d'éviter que les annonces ne soient masquées par les charnières, les encoches et les barres système de l'appareil. Ce processus recalcule également la taille de la bannière adaptative ancrée en utilisant la largeur de la zone de sécurité mise à jour.

L'exemple suivant charge une bannière adaptative ancrée avec la largeur de fenêtre mise à jour lors d'une transition de taille :

Swift

override func viewWillTransition(
  to size: CGSize,
  with coordinator: UIViewControllerTransitionCoordinator
) {
  super.viewWillTransition(to: size, with: coordinator)

  coordinator.animate(alongsideTransition: nil) { [weak self] _ in
    self?.loadBannerAd()
  }
}

@MainActor
func loadBannerAd() {
  let frame = view.frame.inset(by: view.safeAreaInsets)
  let viewWidth = frame.size.width

  bannerView.adSize = largeAnchoredAdaptiveBanner(width: viewWidth)

  let request = Request()
  request.scene = view.window?.windowScene
  bannerView.load(request)
}

SwiftUI

struct MultiSceneBannerView: View {
  var body: some View {
    GeometryReader { geometry in
      let adSize = largeAnchoredAdaptiveBanner(width: geometry.size.width)
      MultiSceneBannerViewContainer(adSize: adSize)
        .frame(width: adSize.size.width, height: adSize.size.height)
    }
  }
}

private struct MultiSceneBannerViewContainer: UIViewRepresentable {
  let adSize: AdSize

  func makeUIView(context: Context) -> BannerView {
    let bannerView = BannerView(adSize: adSize)
    let request = Request()
    request.scene =
      UIApplication.shared.connectedScenes
      .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
    bannerView.load(request)
    return bannerView
  }

  func updateUIView(_ uiView: BannerView, context: Context) {
    if uiView.adSize.size != adSize.size {
      uiView.adSize = adSize
      let request = Request()
      request.scene = uiView.window?.windowScene
      uiView.load(request)
    }
  }
}

Objective-C

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

  [coordinator
      animateAlongsideTransition:nil
                      completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
                        [self loadBannerAd];
                      }];
}

- (void)loadBannerAd {
  dispatch_async(dispatch_get_main_queue(), ^{
    CGRect frame = UIEdgeInsetsInsetRect(self.view.frame, self.view.safeAreaInsets);
    CGFloat viewWidth = frame.size.width;

    self.bannerView.adSize = GADLargeAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth);

    GADRequest *request = [GADRequest request];
    request.scene = self.view.window.windowScene;
    [self.bannerView loadRequest:request];
  });
}

Annonces natives

Vous contrôlez la mise en page des annonces natives. Contrairement aux bannières ou aux annonces en plein écran, vous n'avez pas besoin de recharger les annonces natives lorsque la fenêtre est redimensionnée. Utilisez des contraintes de mise en page automatique standards ou des mises en page SwiftUI pour que la vue de l'annonce native s'adapte aux changements de taille.