Admite varias ventanas y dispositivos plegables

Las aplicaciones que admiten varias ventanas en iPad o que se ejecutan en dispositivos plegables, como el iPhone Duo, pueden mostrar la IU en tamaños de ventana y configuraciones de pantalla dinámicos. En iPad, los usuarios pueden interactuar con varias copias simultáneas de la IU de una app y cambiar el tamaño de las ventanas. En los dispositivos plegables, el estado de plegado determina la pantalla activa. Cuando se despliega, el dispositivo usa la pantalla interior más grande. Cuando está plegado, el dispositivo usa la pantalla exterior más pequeña.

En esta guía, se explica cómo cargar y renderizar anuncios en entornos multiventana y pantallas plegables.

Requisitos previos

Antes de comenzar, completa lo siguiente:

Cómo configurar la escena de la ventana en una solicitud de anuncio

Para recibir un anuncio que se ajuste a una ventana o pantalla activa específica, asigna el objeto UIWindowScene activo a la propiedad scene del objeto GADRequest. Google Mobile Ads SDK devuelve un anuncio con el tamaño adecuado para esa escena. En SwiftUI, consulta las escenas conectadas para la escena de la ventana activa en primer plano.

En el siguiente ejemplo, se configura la escena de la ventana, se carga un anuncio intersticial si se realiza correctamente y se registra un mensaje de error si falla:

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 el modo de prueba, las solicitudes de anuncios fallan con el siguiente error si tu app de varias escenas solicita un anuncio sin pasar una escena:

<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 el modo de producción, la solicitud de anuncio se completa, pero no se presenta el anuncio si se muestra en una ventana más pequeña que el tamaño del contenido del anuncio:

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

Crea la solicitud de anuncio

Cuando se envían solicitudes de anuncios, las aplicaciones de varias escenas requieren una escena de ventana válida. Donde se propaga la escena de la ventana, crea solicitudes de anuncios con el método viewDidAppear. Recomendamos este proceso porque aún no se agrega una vista a una ventana en el método viewDidLoad.

Si bien puedes llamar al método viewDidAppear más de una vez en el ciclo de vida de una app, debes unir la solicitud de anuncio en una marca booleana para que se ejecute solo una vez.

En el siguiente ejemplo, se inicializa la solicitud de anuncio en el método 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;
  }
}

Cómo controlar el cambio de tamaño de la ventana

Las dimensiones de la ventana cambian cuando los usuarios cambian el tamaño de las escenas en el iPad o pliegan y despliegan un dispositivo plegable, como el iPhone Duo. Cuando cambie el tamaño de la ventana, verifica que los anuncios cargados se ajusten a las dimensiones actualizadas y vuelve a cargarlos si es necesario.

Para verificar que los anuncios cargados se ajusten a las dimensiones actualizadas, usa cualquiera de los siguientes métodos:

Anuncios de pantalla completa

Para verificar si un anuncio de pantalla completa cargado sigue siendo válido para el tamaño de la ventana o el estado de plegado actualizados, usa el método canPresentFromRootViewController:error:. Si la verificación falla, carga un anuncio con el tamaño de la escena actualizada.

En el siguiente ejemplo, se verifica si se puede mostrar un anuncio intersticial después de una transición de tamaño y, si es necesario, se vuelve a cargar el anuncio:

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];
                        }
                      }];
}

Controla el cambio de tamaño de la ventana y las transiciones de plegado de manera similar a la rotación del dispositivo. Limita las vistas de banners a la propiedad safeAreaLayoutGuide. Este proceso permite que los anuncios se mantengan alejados de las bisagras, los recortes y las barras del sistema del dispositivo. Este proceso también vuelve a calcular el tamaño del banner adaptable fijo con el ancho actualizado del área segura.

En el siguiente ejemplo, se carga un banner adaptable fijo con el ancho de ventana actualizado durante una transición de tamaño:

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

Anuncios nativos

Tú controlas el diseño de los anuncios nativos. A diferencia de los banners o los anuncios de pantalla completa, no es necesario que vuelvas a cargar los anuncios nativos cuando se cambia el tamaño de la ventana. Usa restricciones estándar de diseño automático o diseños de SwiftUI para que la vista de anuncio nativo se adapte a los cambios de tamaño.