Applications that support [multiple
windows](https://developer.apple.com/documentation/uikit/app_and_environment/scenes)
on iPad or run on foldable devices, such as the iPhone Duo, can display UI
across dynamic window sizes and screen configurations. On iPad, users can
interact with multiple concurrent copies of an app's UI and resize windows. On
foldable devices, the device's fold state determines the active screen. When
unfolded, the device uses the larger inner display. When folded, the device uses
the smaller outer display.

This guide covers loading and rendering ads across multi-window environments and
foldable displays.

## Prerequisites

Before you begin, complete the following:

- Enable scene support in your project. For details, see [Specifying the
  scenes your app
  supports](https://developer.apple.com/documentation/uikit/app_and_environment/scenes/specifying_the_scenes_your_app_supports).
  - Implement at least one ad format:
- [App open](https://developers.google.com/admob/ios/app-open.md.txt)
  - [Banner](https://developers.google.com/admob/ios/banner.md.txt)
  - [Interstitial](https://developers.google.com/admob/ios/interstitial.md.txt)
  - [Native](https://developers.google.com/admob/ios/native.md.txt)
  - [Rewarded](https://developers.google.com/admob/ios/rewarded.md.txt)
  - [Rewarded interstitial](https://developers.google.com/admob/ios/rewarded-interstitial.md.txt)

## Set the window scene in an ad request

To receive an ad that fits a specific window or active display, assign the
active `UIWindowScene` object to the `scene` property on the `GADRequest`
object. Google Mobile Ads SDK returns an ad sized for that scene. In SwiftUI, query
connected scenes for the active foreground window scene.

The following example configures the window scene, loads an interstitial ad on
success, and logs an error message on failure:

### Swift

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

```swift
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

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

> [!IMPORTANT]
> **Key Point:** After you've enabled scene support, set the `scene` property on every ad request, regardless of ad format.

In test mode, ad requests fail with the following error if your multi-scene app
requests an ad without passing a scene:

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

In production mode, the ad request fills, but presenting the ad fails if the ad
is presented on a window smaller than the ad content size:

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

## Build the ad request

When sending ad requests, multi-scene applications require a valid window scene.
Where the window scene is populated, build ad requests using the `viewDidAppear`
method. We recommend this process because a view is not yet added to a window in
the `viewDidLoad` method.

While you can call the `viewDidAppear` method more than once in an app's
lifecycle, you must wrap the ad request in a boolean flag to run only once.

The following example initializes the ad request in the `viewDidAppear` method:

### Swift

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

### Objective-C

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

## Handle window resizing

Window dimensions change when users resize scenes on iPad or fold and unfold a
foldable device such as the iPhone Duo. When the window size changes, verify
that loaded ads fit the updated dimensions and reload the ads if necessary.

To verify that loaded ads fit the updated dimensions, use either of the
following methods:

- [`viewWillTransitionToSize:withTransitionCoordinator:`](https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransitiontosize): detects when the view controller's window rotates, resizes, or transitions between fold states.
- [`windowScene:didUpdateCoordinateSpace:interfaceOrientation:traitCollection:`](https://developer.apple.com/documentation/uikit/uiwindowscenedelegate/3198094-windowscene): for window scene changes.

### Full-screen ads

To verify whether a loaded full-screen ad remains valid for the updated window
size or fold state, use the `canPresentFromRootViewController:error:` method. If
the check fails, load an ad sized for the updated scene.

The following example checks whether an interstitial ad can show after a size
transition and reloads the ad if necessary:

### Swift

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

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

### Banner ads

Handle window resizing and fold transitions similar to device rotation. Limit
banner views to the `safeAreaLayoutGuide` property. This process lets ads remain
clear of device hinges, cutouts, and system bars. This process also recalculates
the anchored adaptive banner size using the updated safe area width.

> [!NOTE]
> **Note:** In Google Mobile Ads SDK 13.11.0 or later, you must call the `GADPortraitAnchoredAdaptiveBannerAdSizeWithWidth` and `GADLandscapeAnchoredAdaptiveBannerAdSizeWithWidth` functions on the main queue.

The following example loads an anchored adaptive banner with the updated window
width during a size transition:

### Swift

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

```swift
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

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

### Native ads

You control the layout of native ads. Unlike banners or full-screen ads, you
don't need to reload native ads when the window resizes. Use standard Auto
Layout constraints or SwiftUI layouts for the native ad view to adapt to size
changes.