Applications that support multiple windows 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.
- Implement at least one ad format:
- App open
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 GAMRequest
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
func loadAdManagerInterstitial() async {
let request = AdManagerRequest()
request.scene = view.window?.windowScene
do {
adManagerInterstitial = try await AdManagerInterstitialAd.load(
with: "/21775744923/example/interstitial", request: request)
} catch {
print("Failed to load interstitial ad with error: \(error.localizedDescription)")
}
}
SwiftUI
func loadAdManagerInterstitial() async {
let request = AdManagerRequest()
request.scene =
UIApplication.shared.connectedScenes
.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
do {
let _ = try await AdManagerInterstitialAd.load(
with: "/21775744923/example/interstitial", request: request)
} catch {
print("Failed to load interstitial ad with error: \(error.localizedDescription)")
}
}
Objective-C
- (void)loadAdManagerInterstitial {
GAMRequest *request = [GAMRequest request];
request.scene = self.view.window.windowScene;
[GAMInterstitialAd loadWithAdManagerAdUnitID:@"/21775744923/example/interstitial"
request:request
completionHandler:^(GAMInterstitialAd *ad, NSError *error) {
if (error) {
NSLog(@"Failed to load interstitial ad with error: %@",
[error localizedDescription]);
return;
}
self.adManagerInterstitial = ad;
}];
}
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
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;
}
}
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:: detects when the view controller's window rotates, resizes, or transitions between fold states.windowScene:didUpdateCoordinateSpace:interfaceOrientation:traitCollection:: 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
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];
}
}];
}
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.
The following example loads an anchored adaptive banner with the updated window width during a size transition:
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 = AdManagerRequest()
request.scene = view.window?.windowScene
bannerView.load(request)
}
SwiftUI
struct MultiSceneAdManagerBannerView: View {
var body: some View {
GeometryReader { geometry in
let adSize = largeAnchoredAdaptiveBanner(width: geometry.size.width)
MultiSceneAdManagerBannerViewContainer(adSize: adSize)
.frame(width: adSize.size.width, height: adSize.size.height)
}
}
}
private struct MultiSceneAdManagerBannerViewContainer: UIViewRepresentable {
let adSize: AdSize
func makeUIView(context: Context) -> AdManagerBannerView {
let bannerView = AdManagerBannerView(adSize: adSize)
let request = AdManagerRequest()
request.scene =
UIApplication.shared.connectedScenes
.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
bannerView.load(request)
return bannerView
}
func updateUIView(_ uiView: AdManagerBannerView, context: Context) {
if uiView.adSize.size != adSize.size {
uiView.adSize = adSize
let request = AdManagerRequest()
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);
GAMRequest *request = [GAMRequest 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.