멀티 윈도우 및 폴더블 지원

iPad에서 여러 창을 지원하거나 iPhone Duo와 같은 폴더블 기기에서 실행되는 애플리케이션은 동적 창 크기와 화면 구성에서 UI를 표시할 수 있습니다. iPad에서 사용자는 앱 UI의 여러 동시 사본과 상호작용하고 창 크기를 조절할 수 있습니다. 폴더블 기기에서는 기기의 접기 상태에 따라 활성 화면이 결정됩니다. 펼치면 기기는 더 큰 내부 디스플레이를 사용합니다. 접힌 상태에서는 기기가 더 작은 외부 디스플레이를 사용합니다.

이 가이드에서는 멀티 윈도우 환경과 폴더블 디스플레이에서 광고를 로드하고 렌더링하는 방법을 설명합니다.

기본 요건

시작하기 전에 다음을 완료하세요.

광고 요청에서 창 장면 설정하기

특정 창 또는 활성 디스플레이에 맞는 광고를 수신하려면 활성 UIWindowScene 객체를 GADRequest 객체의 scene 속성에 할당합니다. Google Mobile Ads SDK는 장면에 적합한 크기의 광고를 반환합니다. SwiftUI에서 활성 포그라운드 창 장면에 대해 연결된 장면을 쿼리합니다.

다음 예에서는 창 장면을 구성하고, 성공 시 전면 광고를 로드하고, 실패 시 오류 메시지를 로깅합니다.

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

테스트 모드에서 멀티 장면 앱이 장면을 전달하지 않고 광고를 요청하면 광고 요청이 실패하고 다음 오류가 발생합니다.

<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.

프로덕션 모드에서는 광고 요청이 채워지지만 광고가 광고 콘텐츠 크기보다 작은 창에 표시되면 광고가 표시되지 않습니다.

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

광고 요청 빌드

광고 요청을 전송할 때 멀티 장면 애플리케이션에는 유효한 창 장면이 필요합니다. 창 장면이 채워진 경우 viewDidAppear 메서드를 사용하여 광고 요청을 빌드합니다. viewDidLoad 메서드에서 뷰가 아직 창에 추가되지 않았으므로 이 프로세스를 사용하는 것이 좋습니다.

앱의 수명 주기에서 viewDidAppear 메서드를 두 번 이상 호출할 수 있지만, 광고 요청을 불리언 플래그로 래핑하여 한 번만 실행해야 합니다.

다음 예에서는 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;
  }
}

창 크기 조절 처리

사용자가 iPad에서 장면 크기를 조절하거나 iPhone Duo와 같은 폴더블 기기를 접고 펼치면 창 크기가 변경됩니다. 창 크기가 변경되면 로드된 광고가 업데이트된 크기에 맞는지 확인하고 필요한 경우 광고를 새로고침합니다.

로드된 광고가 업데이트된 크기에 맞는지 확인하려면 다음 방법 중 하나를 사용하세요.

전체 화면 광고

로드된 전체 화면 광고가 업데이트된 창 크기 또는 접기 상태에 대해 유효한지 확인하려면 canPresentFromRootViewController:error: 메서드를 사용하세요. 검사에 실패하면 업데이트된 장면에 맞는 크기의 광고를 로드합니다.

다음 예에서는 크기 전환 후 전면 광고를 표시할 수 있는지 확인하고 필요한 경우 광고를 다시 로드합니다.

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

기기 회전과 유사하게 창 크기 조절 및 접기 전환을 처리합니다. 배너 조회수를 safeAreaLayoutGuide 속성으로 제한합니다. 이 프로세스를 통해 광고가 기기 힌지, 컷아웃, 시스템 표시줄을 가리지 않습니다. 이 프로세스는 업데이트된 안전 영역 너비를 사용하여 적응형 앵커 배너 크기도 다시 계산합니다.

다음 예에서는 크기 전환 중에 업데이트된 창 너비로 적응형 앵커 배너를 로드합니다.

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

네이티브 광고

네이티브 광고의 레이아웃을 관리할 수 있습니다. 배너 또는 전체 화면 광고와 달리 창 크기가 조절될 때 네이티브 광고를 새로고침할 필요가 없습니다. 네이티브 광고 뷰에 표준 자동 레이아웃 제약 조건 또는 SwiftUI 레이아웃을 사용하여 크기 변경에 맞게 조정합니다.